1. Trang chủ
  2. » Công Nghệ Thông Tin

Tài liệu 8 Network Programming pdf

34 357 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Network Programming
Trường học University of Information Technology
Chuyên ngành Network Programming
Thể loại Tài liệu
Định dạng
Số trang 34
Dung lượng 122 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Public Module DownloadTest Public Sub Main Dim Url As String = "http://www.prosetech.com/index.html" ’ Create the request.. The following sample code uses this regular expression to r

Trang 1

8 Network Programming

The need for computers and devices to communicate across a network is one of the key

ingredients of enterprise programming In its relentless goal to simplify programming,

the NET Framework includes a slew of new networking classes that are logical, efficient, and consistent

The only drawback to networking with NET is that no single dominant model exists In this chapter, you’ll learn how to manage network interaction using sockets (recipes 8.8 to 8.11), but you won’t learn about two higher-level distributed programming frameworks— Web Services and NET Remoting—which have their own dedicated chapters later in this book Typically, socket-based network programming is ideal for closed systems that don’t require interoperability, where developers want to have complete flexibility to tailor communication and control the data before it hits the wire

Of course, this chapter doesn’t concentrate exclusively on socket programming You’ll also learn about Web interaction, such as downloading a Web page from the Internet (recipe 8.5) or a single piece of information (recipe 8.6) You’ll also learn how to retrieve Web connectivity information for the current computer, look up Internet Protocol (IP) addresses and domain names, and ping another computer to gauge its response time At the end of this chapter, two recipes (8.13 and 8.14) show how you can build on the Transmission Control Protocol (TCP) classes included with NET to work with higher- level protocols such as Post Office Protocol 3 (POP3) for e-mail and File Transfer

Protocol (FTP) for transferring files

8.1 Get Web Connectivity Information for the Current Computer

The InternetGetConnectedState function returns True if the current computer is

configured to access the Internet It also returns a dwFlags parameter that specifies the

type of connection using one (or more) of a series of constants

The following Console application defines the InternetGetConnectedState function and

uses it to test the current computer’s connectivity:

Public Module GetInternetState

Trang 2

’ Declare the API function.

Private Declare Function InternetGetConnectedState Lib "wininet" _ (ByRef dwFlags As Long, ByVal dwReserved As Long) As Long

’ Define the possible types of connections

Private Enum ConnectStates

Public Sub Main()

’ Get the connected status

Dim dwFlags As Long

Dim Connected As Boolean = _

Dim ConnectionType As ConnectStates

For Each ConnectionType In _

A sample output is shown here:

This computer is connected to the Internet

Connection flags: LAN

Notice that the InternetGetConnectedState reflects how the computer is configured It

doesn’t reflect whether the computer is configured correctly (in other words, whether the Internet connection is actually working)

8.2 Get the IP Address of the Current Computer

Problem

Trang 3

You want to retrieve the IP address of the current computer, perhaps to use later in networking code

Solution

Use the System.Net.Dns class, which provides shared GetHostName and GetHostByName

methods

Discussion

The Dns class provides domain name resolution services You can invoke its

GetHostName to retrieve the host name for the current computer You can then translate the host name into an IP address using GetHostByName

Dim HostName As String

Dim IPAddress As String

‘ Look up the host name and IP address

HostName = System.Net.Dns.GetHostName()

IPAddress = System.Net.Dns.GetHostByName(HostName).AddressList(0).ToString()

Console.WriteLine("Host name:" & HostName)

Console.WriteLine("IP address:" & IPAddress)

Be aware that the GetHostByName method returns a list of usable IP addresses In most

cases, this address list will contain only one entry

If you run this code, you’ll see something like this:

Host name: fariamat

Trang 4

Internet backbone To perform a DNS lookup, the computer might contact its cache or a DNS sever (which might in turn forward the request to a DNS root server)

This entire process is transparent if you use the System.Net.Dns class, which allows you

to retrieve the IP address for a host name by calling GetHostByName Here’s how you might retrieve the list of IP addresses mapped to http://www.yahoo.com:

A ping message contacts a device at a specific IP address, sends a test message, and

requests that the remote device respond by echoing back the packet You can measure the time taken for a ping response to be received to gauge the connection latency between two computers

Despite the simplicity of ping messages compared to other types of network

communication, implementing a ping utility in NET requires a significant amount of complex low-level networking code The NET class library doesn’t have a prebuilt solution—instead, you must use raw sockets

However, at least one developer has solved the ping problem Lance Olson, a developer

at Microsoft, has provided C# code that allows you to ping a host by name or IP address and measure the milliseconds taken for a response This code has been adapted into a

PingUtility component, which is available with the code in this book’s sample files

To use the ping utility, you must first add a reference to the PingUtility.dll assembly You

can then use the shared Pinger.GetPingTime method with an IP address or domain name The GetPingTime method returns the number of milliseconds that elapse before a

response is received

Trang 5

Console.WriteLine("Milliseconds to contact www.yahoo.com: " & _

NOTE

A ping attempt might not succeed if a firewall forbids it For example, many heavily trafficked sites ignore ping requests because they’re wary of being swamped by a flood of simultaneous pings that will tie up the server (in essence, a denial of service attack).

8.5 Download a File Using HTTP

Discussion

Downloading a file from the Web takes the following four basic steps:

1 Use the shared Create method of the System.Net.WebRequest class to specify the page you want This method returns a WebRequest-derived object, depending on

the type of Uniform Resource Identifier (URI) you use For example, if you use

an HTTP URI (with the scheme http://), it will create an HttpWebRequest

instance If you use a file system URI (with the scheme file://), it will create a

FileWebRequest instance

2 Use the GetResponse method of the HttpWebRequest object to return a

WebResponse object for the page

3 Create a StreamReader or BinaryReader for the WebResponse stream

4 Perform any steps you need to with the stream, such as writing it to a file

The following code is a test application that retrieves and displays the HTML of a Web

page For it to work, you must import both the System.Net and the System.IO namespaces.

Trang 6

Public Module DownloadTest

Public Sub Main()

Dim Url As String = "http://www.prosetech.com/index.html"

’ Create the request

Dim PageRequest As HttpWebRequest = _

CType(WebRequest.Create(Url), HttpWebRequest)

’ Get the response

’ This takes the most significant amount of time, particularly ’ if the file is large, because the whole response is retrieved Dim PageResponse As WebResponse = PageRequest.GetResponse() Console.WriteLine("Response received.")

’ Read the response stream

Dim r As New StreamReader(PageResponse.GetResponseStream()) Dim Page As String = r.ReadToEnd()

WebRequest.BeginGetResponse, which doesn’t block your code and calls a callback

procedure when the response has been retrieved

8.6 Retrieve a Single Piece of Information from a Web Page

You can extract information from a Web stream in several ways You could read through

the stream, use methods of the String class such as IndexOf, or apply a regular

expression The latter of these—using a regular expression—is the most flexible and powerful

Trang 7

The first step is to create a regular expression that filters out the information you need Recipe 1.17 provides several examples and a reference to basic regular expression syntax.

For example, most Web pages include a text title that is stored in a <title></title> tag

To retrieve this piece of information, you use the following regular expression:

<title>(?<match>.*?)</title>

This expression retrieves all the text between the opening and closing <title> tag and places it in a named group called match The following sample code uses this regular

expression to retrieve the title from a URL the user enters It requires three namespace

imports: System.Net, System.IO, and System.Text RegularExpressions

Public Module ExtractTitleTest

Public Sub Main()

Console.WriteLine("Enter a URL, and press Enter.")

Console.Write(">")

Dim Url As String = Console.ReadLine()

Dim Page As String

Try

’ Create the request

Dim PageRequest As HttpWebRequest = _

CType(WebRequest.Create(Url), HttpWebRequest)

’ Get the response

’ This takes the most significant amount of time, particularly

’ if the file is large, because the whole response is retrieved

Dim PageResponse As WebResponse = PageRequest.GetResponse() Console.WriteLine("Response received.")

’ Read the response stream

Dim r As New StreamReader(PageResponse.GetResponseStream()) Page = r.ReadToEnd()

’ Define the regular expression

Dim TitlePattern As String = "<title>(?<match>.*?)</title>" Dim TitleRegex As New Regex(TitlePattern, _

RegexOptions.IgnoreCase Or RegexOptions.Singleline)

’ Find the title

Dim TitleMatch As Match = TitleRegex.Match(Page)

’ Display the title

If TitleMatch.Success Then

Console.WriteLine("Found title: " & _

Trang 8

Here’s the output for a test run that retrieves the title from the Yahoo! search engine:

Enter a URL, and press Enter

>http://yahoo.com

Response received

Found title: Yahoo!

If the Web page is extremely large, this approach might not be efficient because the entire stream is copied to a string in memory Another option is to read through the stream character-by-character and try to build up a match to a search pattern This approach requires more custom code and is demonstrated in detail with text searching in a file in recipe 5.8

NOTE

Screen scraping solutions such as this one can be quite brittle If the user interface for the Web site changes and the expected pattern is altered, you’ll no longer be able to extract the information you need If you have control over the Web site, you can implement a much more robust approach using a Web service to return the desired information Web services also support the full set of basic data types, which prevents another possible source of errors.

8.7 Find All Links in a Web Page

Trang 9

itself could be relative (in which case it needs to be interpreted relative to the current page), fully qualified (in which case it can have one of countless schemes, including

http:// or file:// or mailto://), or it might just be a bookmark (an anchor tag with an href

that starts with the # character) Dealing with these myriad possibilities isn’t easy

The first step is to craft a suitable regular expression In this case, we’ll consider only the

links that are provided in the href attribute of an anchor tag Here’s one regular

expression that retrieves all href values from a Web page:

href\s*=\s*(?:"(?<match>[^"]*)"|(?<match>\S+))

Another option is to retrieve absolute paths only The following line of code is a slightly

less complicated regular expression that matches href values that start with http://

href\s*=\s*"(?<match>http://.*?)"

The following sample application uses the first option It then manually checks the retrieved URIs to see if they are bookmarks (in which case they are discarded) and to determine if they’re relative or absolute If the bookmarks are relative paths, the

System.Uri class is used with the current page Uri to transform them into fully qualified

paths

Public Module ExtractURITest

Public Sub Main()

Console.WriteLine("Enter a URL, and press Enter.")

Console.Write(">")

Dim Url As String = Console.ReadLine()

Dim BaseUri As Uri

Dim Page As String

Try

BaseUri = New Uri(Url)

’ Create the request

Dim PageRequest As HttpWebRequest = _

CType(WebRequest.Create(Url), HttpWebRequest)

’ Get the response

’ This takes the most significant amount of time, particularly

’ if the file is large, because the whole response is retrieved

Dim PageResponse As WebResponse = PageRequest.GetResponse() Console.WriteLine("Response received.")

’ Read the response stream

Dim r As New StreamReader(PageResponse.GetResponseStream()) Page = r.ReadToEnd()

r.Close()

Catch Err As Exception

Trang 10

Console.WriteLine(Err.ToString())

Console.ReadLine()

Return

End Try

’ Define the regular expression

Dim HrefPattern As String

HrefPattern = "href\s*=\s*(?:""(?<match>[^""]*)""|(?

<match>\S+))"

Dim HrefRegex As New Regex(HrefPattern, _

RegexOptions.IgnoreCase Or RegexOptions.Compiled)

’ Find and display all the href matches

Dim HrefMatch As Match = HrefRegex.Match(Page)

Dim Scheme As String

Scheme = Uri.UriSchemeHttp & "://"

If Link.Substring(0, Scheme.Length) = Scheme Then _ Absolute = True

Scheme = Uri.UriSchemeHttps & "://"

If Link.Substring(0, Scheme.Length) = Scheme Then _ Absolute = True

Scheme = Uri.UriSchemeFile & "://"

If Link.Substring(0, Scheme.Length) = Scheme Then _ Absolute = True

This code investigates each URI by comparing it against a few common schemes

Another approach would be to try to instantiate a new System.Uri instance using the

Trang 11

retrieved URI string If the string is not an absolute path, an error would occur You could catch the resulting exception and respond accordingly

Here’s the partial output for a sample test:

Enter a URL, and press Enter

To create a TCP connection, one computer must act as the server and start listening on a

specific endpoint (An endpoint is defined as an IP address, which identifies the computer

and port number.) The other computer must act as a client and send a connection request

to the endpoint where the first computer is listening Once the connection is established, the two computers can take turns exchanging messages .NET makes this process easy through its stream abstraction Both computers simply write to and read from a

NetworkStream to transmit data

NOTE

Even though a TCP connection always requires a server and a client, there’s no reason an individual application can’t be both For example, in a peer-to-peer application, one

Trang 12

thread is dedicated to listening for incoming requests (acting as a server) while another thread is dedicated to initiate outgoing connections (acting as a client).

Once a TCP connection is established, the two computers can send any type of data by

writing it to the NetworkStream However, it’s a good idea to begin designing a

networked application by defining constants that represent the allowable commands Doing so ensures that your application code doesn’t need to hardcode communication strings

Public Class ServerMessages

Public Const AcknowledgeOK As String = "OK"

Public Const AcknowledgeCancel As String = "Cancel"

Public Const Disconnect As String = "Bye"

End Class

Public Class ClientMessages

Public Const RequestConnect As String = "Hello"

Public Const Disconnect As String = "Bye"

End Class

In this example, the defined vocabulary is very basic You would add more constants depending on the type of application For example, in a file transfer application, you might include a client message for requesting a file The server might then respond with

an acknowledgment and return file details such as the file size These constants must be compiled into a separate class library assembly, which must be referenced by both the

client and server Both the client and the server will also need to import the System.Net, System.Net.Sockets, and System.IO namespaces

The following code is a template for a basic TCP server It listens at a fixed port, accepts the first incoming connection, and then waits for the client to request a disconnect At this

point, the server could call the AcceptTcpClient method again to wait for the next client,

but instead, it simply shuts down

Public Module TcpServerTest

Public Sub Main()

’ Create a new listener on port 8000

Dim Listener As New TcpListener(8000)

Console.WriteLine("About to initialize port.")

Listener.Start()

Console.WriteLine("Listening for a connection ")

Try

’ Wait for a connection request,

’ and return a TcpClient initialized for communication Dim Client As TcpClient = Listener.AcceptTcpClient()

Trang 13

Console.WriteLine("Connection accepted.")

’ Retrieve the network stream

Dim Stream As NetworkStream = Client.GetStream()

’ Create a BinaryWriter for writing to the stream

Dim w As New BinaryWriter(Stream)

’ Create a BinaryReader for reading from the stream

Dim r As New BinaryReader(Stream)

If r.ReadString() = ClientMessages.RequestConnect Then

requires two ports: one at the server end, and one at the client end However, only the server port needs to be specified The client port can be chosen dynamically at runtime

from the available ports, which is what the TcpClient class will do by default

Public Module TcpClientTest

Public Sub Main()

Dim Client As New TcpClient()

Try

Console.WriteLine("Attempting to connect to the server " & _ "on port 8000.")

Trang 14

Client.Connect(IPAddress.Parse("127.0.0.1"), 8000) Console.WriteLine("Connection established.")

’ Retrieve the network stream

Dim Stream As NetworkStream = Client.GetStream() ’ Create a BinaryWriter for writing to the stream Dim w As New BinaryWriter(Stream)

’ Create a BinaryReader for reading from the stream Dim r As New BinaryReader(Stream)

Here’s a sample connection transcript on the server side:

About to initialize port

Listening for a connection

And here’s a sample connection transcript on the client side:

Attempting to connect to the server on port 8000

Connection established

Connected

Press Enter to disconnect

Trang 15

For example, consider the basic TCP client and server classes shown in recipe 8.8 You can convert the server into a multithreaded server that supports multiple simultaneous connections quite easily First create a class that will interact with an individual client: Public Class ClientHandler

Private Client As TcpClient

Public Sub Start()

’ Retrieve the network stream

Dim Stream As NetworkStream = Client.GetStream()

’ Create a BinaryWriter for writing to the stream

Dim w As New BinaryWriter(Stream)

’ Create a BinaryReader for reading from the stream

Dim r As New BinaryReader(Stream)

If r.ReadString() = ClientMessages.RequestConnect Then

w.Write(ServerMessages.AcknowledgeOK)

Console.WriteLine(ID & ": Connection completed.")

Do

Loop Until r.ReadString() = ClientMessages.Disconnect

Console.WriteLine(ID & ": Disconnect request received.") w.Write(ServerMessages.Disconnect)

Trang 16

Next modify the server code so that it loops continuously, creating new ClientHandler

instances as required and launching them on new threads Here’s the revised code:

Dim ClientNum As Integer

Do

Try

’ Wait for a connection request,

’ and return a TcpClient initialized for communication

Dim Client As TcpClient = Listener.AcceptTcpClient()

Console.WriteLine("Server: Connection accepted.")

’ Create a new object to handle this connection

ClientNum += 1

Dim Handler As New ClientHandler(Client, "Client " & _

ClientNum.ToString())

’ Start this object working on another thread

Dim HandlerThread As New System.Threading.Thread( _

AddressOf Handler.Start)

HandlerThread.IsBackground = True

HandlerThread.Start()

’ (You could also add the Handler and HandlerThread to

’ a collection to track client sessions.)

Catch Err As Exception

Console.WriteLine(Err.ToString())

End Try

Loop

The following code shows the server-side transcript of a session with two clients:

Server: About to initialize port

Server: Listening for a connection

Server: Connection accepted

Client 1: Connection completed

Server: Connection accepted

Client 2: Connection completed

Client 2: Disconnect request received

Client 2: Client connection closed

Client 1: Disconnect request received

Client 1: Client connection closed

Trang 17

You might want to add additional code to the network server so that it tracks the current worker objects in a collection Doing so would allow the server to abort these tasks if it needs to shut down and enforce a maximum number of simultaneous clients For more information, see the multithreading recipes in Chapter 7

8.10 Communicate Using UDP

of its lower overhead, UDP is often used for "chatty" applications where it’s acceptable

to lose some messages For example, imagine you want to create a network where

individual clients send information about the current temperature at their location to a server every few minutes You might use UDP in this case because the communication frequency is high and the damage caused by losing a packet is trivial (because the server can just continue to use the last received temperature reading)

The UDP template application shown in the following code uses two threads: one to receive messages, and one to send them To test this application, load two instances at the same time On computer A, specify the IP address for computer B On computer B, specify the address for computer A You can then send text messages back and forth at will (You can simulate a test on a single computer by using two different ports and the loopback IP address 127.0.0.1.)

Public Module UdpTest

Private LocalPort As Integer

Public Sub Main()

’ Define endpoint where messages are sent

Console.WriteLine("Connect to IP: ")

Dim IP As String = Console.ReadLine()

Dim Port As Integer = 8800

Dim RemoteEndPoint As New IPEndPoint(IPAddress.Parse(IP), _ Port)

’ Define local endpoint (where messages are received)

LocalPort = 8800

Ngày đăng: 27/01/2014, 14:20

TỪ KHÓA LIÊN QUAN

w