Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 53 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
53
Dung lượng
1,19 MB
Nội dung
Thread t = new Thread(new ThreadStart(worker.WorkerThreadProc)); t.Start(); } Thread.Sleep(200); } } catch (SocketException ex) { MessageBox.Show(ex.ToString()); } } private void WorkerThreadProc() { TcpClient client = null; NetworkStream ns = null; try { int size = 0; int buffer_len = 1024; byte[] buffer = new byte[buffer_len]; //Message to the client string hello = “Ping From Server\r\n”; byte[] res = System.Text.Encoding.ASCII.GetBytes(hello); int res_len = res.Length; //The server blocks here, waiting for a client client = myForm.myServer.AcceptTcpClient(); //Here comes a client ns = client.GetStream(); //Send our “Ping” message ns.Write(res, 0, res_len); //Receive “Pong” message from the client while ((size = ns.Read(buffer, 0, buffer_len)) > 0) { data += System.Text.Encoding.ASCII.GetString(buffer, 0, size); } //Update UI using the delegate method myForm.Invoke(new InvokeDelegate(InvokeMethod)); } catch (SocketException ex) { MessageBox.Show(ex.ToString()); } catch (IOException ex) { MessageBox.Show(ex.ToString()); } finally { ns.Close(); client.Close(); 186 Chapter 7 12_762935 ch07.qxp 11/20/06 7:56 AM Page 186 } } //This method will run in the context of the UI thread //Don’t place network processing code here because it will block UI update private void InvokeMethod() { myForm.UpdateLog(“Connected to a client\r\n”); myForm.UpdateLog(data); } } } This example doesn’t use an additional UI update thread in the TcpClient because its operations are not sophisticated; you don’t need to update the UI while waiting for the server’s response. If you have some more controls on the UI and would allow the user to access the controls while the TcpClient blocks for the server’s response, you need to place the TcpClient-related tasks into a thread other than the main UI thread (the form thread). Network Sockets The TcpListener class does not provide all the socket-level functionality, such as socket options, socket polling, and selection. If a pluggable protocol requires more flexible control over network connections on the socket level, a TcpListener does not suffice. For this purpose, you can use the System.Net .Sockets.Socket class, which implements the Berkeley socket interface. TcpListener and TcpClient are actually wrappers of a Socket class. Unlike the TcpListener and TcpClient classes, which support only TCP, a Socket class can be associ- ated with a list of protocol types defined in the Socket.ProtocolType enumeration. Some of the proto- cols that may be used for Smartphone application development are TCP, UDP, IP, IPv6, ICMP, and Raw. The Raw protocol type enables you to implement your own network layer protocols. The Socket class provides both synchronous and asynchronous data transfer between two communica- tion endpoints. Synchronous methods such as Send(), SendTo(), Receive(), and ReceiveFrom() have their asynchronous counterparts: BeginSend() and EndSend(), BeginSendTo() and EndSendTo(), BeginReceive() and EndReceive(), and BeginReceiveFrom() and EndReceiveFrom(). The constructor of a Socket object requires three parameters: public Socket( AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType); AddressFamily indicates the address for the socket. Frequently used address families for Smartphone development are AddressFamily.InterNetwork, AddressFamily.InterNetworkV6, and Address Family.Irda . 187 Networking 12_762935 ch07.qxp 11/20/06 7:56 AM Page 187 SocketType could be one of the following widely used socket types: Dgram for UDP-based connection- less, unreliable communication; Stream for TCP-based, connection-oriented, reliable, and duplex com- munication; and Raw for protocol implementations that require the developer to handle IP headers. In addition, the .NET Compact Framework supports two extended socket types: Rdm for connectionless but reliable and in-order message delivery, and Seqpacket for connection-oriented and in-order message delivery. Note that Steam socket types do not guarantee in-order delivery of messages. As you can see, some socket types implicitly specify a ProtocolType. For example, a SocketType of Stream indicates a ProtocolType of Tcp. Conversely, a SocketType of Dgram requires a ProtocolType of Udp. If you pass an incompatible SocketType and ProtocolType, a SocketException will be raised. The following examples create a TCP socket, a UDP socket, and a Raw socket that is used to implement ICMP, respectively: Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp); TCP Sockets Once created, a TCP server socket can be bound to a specific IP address and a port number. Then the server socket can start to listen at a local port using the Listen() method, and accept incoming connec- tion requests using the Accept() method. The Accept() method returns a Socket object that you can further use to send or receive data. A TCP socket can directly connect to a remote TCP server that is listening. TCP Server Sockets The following example demonstrates the common procedure for creating a TCP server socket: //Assuming an IPEndPoint object ipe is created //Create the socket Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //Bind to a local endpoint ServerSocket.Bind(ipe); //Start to listen; this method does not block ServerSocket.Listen(queueLength); //queueLength specifies the number of connections that can be queued //The server socket blocks waiting for an incoming request Socket oneConn = serverSocket.Accept(); The Accept() method will block the calling thread until a connection request is received. Then a second Socket object, oneConn in this example, is created. The initial socket object will continue to queue incoming connection requests. Sending and receiving data over the connected socket is very similar to common I/O operations, with one exception: a SocketFlags parameter can be used to control how the data is sent over the socket. The following are two examples of the overloaded methods: 188 Chapter 7 12_762935 ch07.qxp 11/20/06 7:56 AM Page 188 public int Send(byte[] buffer, SocketFlags flags); public int Receive(byte[] buffer, SocketFlags flags); The Send() operation does not send data to the network; it actually copies data from your buffer to the system’s protocol stack buffer. Similarly, the Receive() operation does not directly pick up data from the network interface; instead, it retrieves data from the protocol stack buffer to the user’s buffer. In both cases, it is the underlying system’s task to eventually send data to the network. The SocketFlags parameter can be a combination of several items of the SocketFlags enumeration, including SocketFlags.None, SocketFlags.DontRoute, SocketFlags.OutOfBand, and so on. The following sample code shows how to send and receive data synchronously over a connected socket oneConn. When the data transfer is over, you need to shut down the socket first, and then close it. The Socket.Shutdown() method will ensure that all data has been sent and received. The Socket .Shutdown() method needs a parameter to indicate whether to disable sending, receiving, or both. Then the Socket.Close() method can be called to release all resources used by the socket. try{ Byte[] message = Encoding.ASCII.GetBytes(“Hello!”); Byte[] buffer = new byte[1024]; OneConn.Send(message, SocketFlags.None); OneConn.Receive(buffer, SocketFlags.None); } catch (SocketExcpetion ex) { } finally { oneConn.Shutdown(SocketShutdown.Both); //Shut down the connection first to ensure all data has been sent oneConn.Close(); //After shutting down the socket, close it } The .NET Framework has an additional method, Disconnect(), in the System.Net.Sockets .Socket class, which disconnects the socket and provides an option for the developer to specify whether the endpoint of the socket can be reused. The Socket class of the .NET Compact Framework does not have this method. In the previous section, you saw code for a desktop Windows TCP server application. Now let’s examine a console-based TCP server also running on desktop Windows. This example is in the TCPConsoleServer project of Chapter 7. The underlying class ServerSocket defines a field of the server socket and three methods: StartServer(), ProcessConnection(), and ShutdownServer(). The StartServer() method creates a server socket object that binds to a local address and port 4400 (you can choose any port as long as it is not used by other programs), and then calls Socket.Accept() waiting for incoming con- nections. When a connection request arrives (from desktop TCP software such as telnet or a Smartphone TCP client, introduced below), a new thread will be created to handle this connection, denoted by a socket object returned by the Accept() method. The ProcessConnection() method first sends a ping message. Then, for each message it receives through the underlying socket, it replies with a pong message. This 189 Networking 12_762935 ch07.qxp 11/20/06 7:56 AM Page 189 sequence will continue until the other side shuts down the connection. If the client forcibly closes the con- nection, a SocketException with an error code of 10054 (connection reset by peer) will be raised. The ProcessConnection() method does not handle this exception because it is considered a normal case; the socket will be shut down and closed without presenting any error message to the user. If, however, another SocketException occurs, the user will see a warning message. using System; using System.Collections.Generic; using System.Text; using System.Net.Sockets; using System.Net; using System.IO; using System.Threading; namespace TCPConsoleServer { class ServerSocket { Socket serverSocket = null; private void StartServer() { Console.WriteLine(“=============”); Console.WriteLine(“TCP server @ “ + IPAddress.Any + “:port 4400”); Console.WriteLine(“=============”); Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); serverSocket.Bind(new IPEndPoint(IPAddress.Any, 4400)); serverSocket.Listen(30); while (true) { Socket oneSocket = serverSocket.Accept(); ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessConnection),oneSocket); } } private void ProcessConnection(object o) { Socket oneSocket = (Socket)o; byte[] buf = new byte[1024]; byte[] message = Encoding.ASCII.GetBytes(“Ping From Server”); try { String remoteEnd = oneSocket.RemoteEndPoint.ToString(); Console.WriteLine(“Got a Client from {0}”, remoteEnd); /* Console.WriteLine(“SO_REUSEADDRESS:” + oneSocket.GetSocketOption( SocketOptionLevel.Socket, SocketOptionName.ReuseAddress)); Console.WriteLine(“This application will timeout if Send does not return within “ + oneSocket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout)); */ 190 Chapter 7 12_762935 ch07.qxp 11/20/06 7:56 AM Page 190 oneSocket.Send(message); Console.WriteLine(“Send Ping to {0}”, remoteEnd); int size = 0; do { size = oneSocket.Receive(buf, 1024, SocketFlags.None); if (size > 0) { Console.WriteLine(“\r\nReceived from {0}”, remoteEnd); String tmp = Encoding.ASCII.GetString(buf, 0, size); Console.Write(tmp); //Check to see if a line of message is received if(tmp.IndexOf(“\r\n”) >= 0) oneSocket.Send(message); //Send “Ping” for each received message } } while (size > 0); Console.WriteLine(); } catch (SocketException sockEx) { //Skip the exception that was raised when a client forcibly closes the socket if(sockEx.ErrorCode != 10054) Console.WriteLine(“\r\nException Code: {0} : {1}”, sockEx.ErrorCode, sockEx.Message); } catch (IOException ioEx) { Console.WriteLine(ioEx.Message); } finally { oneSocket.Shutdown(SocketShutdown.Both); oneSocket.Close(); } } private void ShutdownServer() { if (serverSocket.Connected) { serverSocket.Shutdown(SocketShutdown.Both); serverSocket.Disconnect(true); //Close the server socket and allow reuse of the port } } static void Main(string[] args) { ServerSocket myServer = new ServerSocket(); myServer.StartServer(); } } } 191 Networking 12_762935 ch07.qxp 11/20/06 7:56 AM Page 191 Figure 7-6 shows an example of the output of the TCP console server. Figure 7-6 TCP Client Sockets A TCP client socket does not listen at a port. Once created, you need to call the Connect() method to connect an endpoint. After that, you can use Send() and Receive() for data transfer, as shown in the TCP server socket. The following code snippet shows a TCP client that is connected to a remote endpoint and receives data: //Assuming an IPEndPoint ipe has been created mySock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); mySock.Connect(ipe); try { byte[] buf = new byte[1024]; int size = 0; do { size = mySock.Receive(buf, 1024, SocketFlags.None); if (size > 0) { //Consume received data } } while (size > 0); } catch (SocketException sockEx) { } For a Smartphone application with a GUI, it is common to place the data reception code of a socket into a separate thread other than the main UI thread. This can be done using a ThreadPool. Sending data from the socket is often triggered by some controls on the UI. For example, when a user selects some local data and clicks a button, the click event handler of the button will start the Send operation. 192 Chapter 7 12_762935 ch07.qxp 11/20/06 7:56 AM Page 192 The following is an example of a TCP socket client that communicates with the aforementioned TCP console server. As shown in the first screen of Figure 7-7, the main UI features a windows form contain- ing a text box showing the message log and two menu items, Send a Msg and Connection. The Connection menu item has two submenu items, Connect and Exit. Note that in the .NET Compact Framework, only the right menu of a windows form can have submenus. When the program starts, the Send a Msg menu item is temporarily disabled. Users must first select Connection ➪Connect to make a connection to a predefined server. Once connected, they can start to send a message by clicking Send a Msg. A new form will show on the screen (the second screen in Figure 7-7). Here users can enter a mes- sage and send it to the server by clicking Send! Then the main form will show up again, and the message log will be updated to show the user’s sent messages and the messages from the server (the third screen in Figure 7-7). Figure 7-7 The fields and the constructor of the SocketClient class are shown in the following code. The call has a Socket member of mySock and two string members of ReceivedMessage and SendMessage. The dele- gate member of the class is used by a socket thread that runs ReceiveProc()to update the UI control in the context of the main UI thread through Control.Invoke(): public partial class SocketClient : Form { Socket mySock = null; string ReceivedMessage = null; string SendMessage = null; private delegate void InvokeDelegate(); public SocketClient() { InitializeComponent(); mnuSendMessage.Enabled = false; } The Connect menu item event handler and the Connect() routine together make a connection to the server. They are shown as follows. The Connect() method further uses a ThreadPool for the socket ReceiveProc() method: 193 Networking 12_762935 ch07.qxp 11/20/06 7:56 AM Page 193 private void mnuConnect_Click(object sender, EventArgs e) { if (mySock!=null && mySock.Connected) { //Disconnect the socket mySock.Shutdown(SocketShutdown.Both); mySock.Close(); mnuConnect.Text = “Connect”; } else { mnuConnect.Text = “Disconnect”; Connect(); } } private void Connect() { IPEndPoint ipe = new IPEndPoint(IPAddress.Parse(“192.168.0.188”),4400); mySock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); mySock.Connect(ipe); if (mySock.Connected) { mnuSendMessage.Enabled = true; ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveProc)); } else { MessageBox.Show(“Cannot connect to server.”); mnuConnect.Text = “Connect”; } } The ReceiveProc() method performs a blocking Socket.Receive() that continuously reads a fixed length of bytes into a buffer. As long as some data has been received in an iteration, the method will loop for the next Socket.Receive() call. If no data is available (in the protocol stack buffer), then the Socket.Receive() call will block. In some cases the other side closes the connection gracefully (i.e., outstanding data is sent successfully), and then Socket.Receive() returns 0, which will terminate the loop: private void ReceiveProc(Object stateInfo) { try { byte[] buf = new byte[1024]; int size = 0; do { size = mySock.Receive(buf, 1024, SocketFlags.None); if (size > 0) { 194 Chapter 7 12_762935 ch07.qxp 11/20/06 7:56 AM Page 194 ReceivedMessage = Encoding.ASCII.GetString(buf, 0, size); //Update the UI this.Invoke(new InvokeDelegate(InvokeMethod)); } } while (size > 0); } catch (SocketException sockEx) { //Skip the exception that was raised when we close the socket while still receiving if(sockEx.ErrorCode != 10004) MessageBox.Show(sockEx.ErrorCode.ToString() + “:” + sockEx.Message); } } private void InvokeMethod() { txtLog.Text += “\r\nThe Server said: “ + ReceivedMessage; } The SocketClient form must provide a method for the SendMessage form to update the message log from within the SendMessage form. In addition, when a user clicks the Exit submenu, the ongoing socket will be shut down for both sending and receiving, and then closed: public void UpdateSendLog(String myMessage) { SendMessage = myMessage; txtLog.Text += “\r\nI said: “ + SendMessage; } private void mnuExit_Click(object sender, EventArgs e) { try { if (mySock != null) { if (mySock.Connected) { mySock.Shutdown(SocketShutdown.Both); mySock.Close(); } } } catch (SocketException sockEx) { MessageBox.Show(sockEx.ErrorCode.ToString() + “:” + sockEx.Message); } Application.Exit(); } 195 Networking 12_762935 ch07.qxp 11/20/06 7:56 AM Page 195 [...]... sockets, TCP clients, and TCP servers for Smartphone networking applications The following chapter covers Smartphone messaging, including e-mail and SMS You will also learn how to leverage the NET Compact Framework for Smartphone to develop applications accessing personal information management (PIM) data 199 12_7629 35 ch07.qxp 11/20/06 7 :56 AM Page 200 13_7629 35 ch08.qxp 11/20/06 8:24 AM Page 201 E-mail,... the Microsoft. WindowsMobile.PocketOutlook namespace in C#, which can be conceived of as the managed code implementation of the POOM Note that the Microsoft. WindowsMobile.PocketOutlook namespace is currently available only in Windows Mobile 5. 0 and is not supported in Smartphone 2002 and Smartphone 2003 This chapter covers the following topics: ❑ An introduction to POOM and using POOM with C++ ❑ The Microsoft. WindowsMobile.PocketOutlook... SelectPictureDialog object to pick the picture file SelectPictureDialog is a class in the new Microsoft. WindowsMobile.Forms namespace that ships with Windows Mobile 5. 0 Like the Microsoft. WindowsMobile.PocketOutlook namespace, the Microsoft. WindowsMobile.Forms namespace is one of the new features in Windows Mobile 5. 0 and 210 13_7629 35 ch08.qxp 11/20/06 8:24 AM Page 211 E-mail, SMS, and PIM Data is not part of the... book, Mr John Sleeva Start a new Windows Mobile 5. 0 device application in Visual Studio 20 05, and name the project email1 Figure 8 -5 illustrates the simple UI It contains only two menu items: The left soft key triggers the quit event and the right soft key sends the e-mail Figure 8 -5 Before you actually do the coding, don’t forget to add a reference to the Microsoft. WindowsMobile PocketOutlook namespace;... then launch the client on the emulator or a Smartphone using Visual Studio UDP Sockets So far this chapter has used TCP sockets in all the examples to show how to leverage the networking classes in the NET Compact Framework to build Smartphone applications Now let’s look at the facility for another popular type of transport: UDP 196 12_7629 35 ch07.qxp 11/20/06 7 :56 AM Page 197 Networking Because UDP is... APIs 203 13_7629 35 ch08.qxp 11/20/06 8:24 AM Page 204 Chapter 8 Note that the Microsoft. WindowsMobile.PocketOutlook namespace is not part of the NET Compact Framework Therefore, you first need to add the reference to your application To add a reference in a solution or project in Visual Studio 20 05, click Project➪Add Reference In the NET tab of the Add Reference dialog box, choose Microsoft. WindowsMobile.PocketOutlook,... Figure 8-8 Figure 8-9 2 15 13_7629 35 ch08.qxp 11/20/06 8:24 AM Page 216 Chapter 8 Figure 8-10 Accessing PIM Data Users are interested primarily in three major types of PIM data: appointments, contacts, and tasks This section describes a simple application that can populate a ListView control with all the appointments in the calendar application Create a new Windows Mobile 5. 0 Smartphone application and... aSession.Tasks.Items; foreach (Task t in taskItems) { Messagebox.Show(t.subject); } 204 13_7629 35 ch08.qxp 11/20/06 8:24 AM Page 2 05 E-mail, SMS, and PIM Data 3 Release the Outlook session Before closing your application, remember to release the resources by calling the Dispose()method This is necessary because the Microsoft. WindowsMobile PocketOutlook namespace is not part of the NET Compact Framework;... EmailMessage object that says hello to our readers: EmailMessage mesg = new EmailMessage(); mesg.To.Add(recv); mesg.Subject = “Hello”; mesg.BodyText = “Dear readers, we hope you enjoy learning Smartphone programming ; 207 13_7629 35 ch08.qxp 11/20/06 8:24 AM Page 208 Chapter 8 The last action is to send the e-mail out by calling the Send() method of the EmailAccount class, as follows: anEmailAcct.Send(mesg); Depending... with C++ and Win32 API programming The good news is that a number of managed POOM APIs are shipped with the Windows Mobile 5. 0 SDK that greatly simplify your code and make your program easier to manage and understand This book focuses on managed code You will learn how to use those new APIs in the following sections Note, however, that the managed APIs that ship with Windows Mobile 5. 0 do not apply to . sockEx) { MessageBox.Show(sockEx.ErrorCode.ToString() + “:” + sockEx.Message); } Application.Exit(); } 1 95 Networking 12_7629 35 ch07.qxp 11/20/06 7 :56 AM Page 1 95 The SendForm class implements a separate Windows form that enables. per- sonal information management (PIM) data. 199 Networking 12_7629 35 ch07.qxp 11/20/06 7 :56 AM Page 199 12_7629 35 ch07.qxp 11/20/06 7 :56 AM Page 200 E-mail, SMS, and PIM Data The ability to manage. Windows Mobile 5. 0 and is not supported in Smartphone 2002 and Smartphone 2003. This chapter covers the following topics: ❑ An introduction to POOM and using POOM with C++ ❑ The Microsoft. WindowsMobile.PocketOutlook