基于C#的socket編程的TCP異步實(shí)現(xiàn)(轉(zhuǎn))

一嫉鲸、摘要
  本篇博文闡述基于TCP通信協(xié)議的異步實(shí)現(xiàn)遇西。

二哼绑、實(shí)驗(yàn)平臺
  Visual Studio 2010

三、異步通信實(shí)現(xiàn)原理及常用方法
3.1 建立連接 
  在同步模式中倒淫,在服務(wù)器上使用Accept方法接入連接請求伙菊,而在客戶端則使用Connect方法來連接服務(wù)器。相對地,在異步模式下镜硕,服務(wù)器可以使用BeginAccept方法和EndAccept方法來完成連接到客戶端的任務(wù)运翼,在客戶端則通過BeginConnect方法和EndConnect方法來實(shí)現(xiàn)與服務(wù)器的連接。

BeginAccept在異步方式下傳入的連接嘗試兴枯,它允許其他動(dòng)作而不必等待連接建立才繼續(xù)執(zhí)行后面程序南蹂。在調(diào)用BeginAccept之前,必須使用Listen方法來偵聽是否有連接請求念恍,BeginAccept的函數(shù)原型為:

BeginAccept(AsyncCallback AsyncCallback, Ojbect state)
參數(shù):

AsyncCallBack:代表回調(diào)函數(shù)

state:表示狀態(tài)信息六剥,必須保證state中包含socket的句柄

使用BeginAccept的基本流程是:
(1)創(chuàng)建本地終節(jié)點(diǎn),并新建套接字與本地終節(jié)點(diǎn)進(jìn)行綁定峰伙;
(2)在端口上偵聽是否有新的連接請求疗疟;
(3)請求開始接入新的連接,傳入Socket的實(shí)例或者StateOjbect的實(shí)例瞳氓。

參考代碼:

//定義IP地址
IPAddress local = IPAddress.Parse("127.0,0,1");
IPEndPoint iep = new IPEndPoint(local,13000);
//創(chuàng)建服務(wù)器的socket對象
Socket server = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
server.Bind(iep);
server.Listen(20);
server.BeginAccecpt(new AsyncCallback(Accept),server);

當(dāng)BeginAccept()方法調(diào)用結(jié)束后策彤,一旦新的連接發(fā)生,將調(diào)用回調(diào)函數(shù)匣摘,而該回調(diào)函數(shù)必須包括用來結(jié)束接入連接操作的EndAccept()方法店诗。

該方法參數(shù)列表為 Socket EndAccept(IAsyncResult iar)

下面為回調(diào)函數(shù)的實(shí)例:

void Accept(IAsyncResult iar)
{
    //還原傳入的原始套接字
    Socket MyServer = (Socket)iar.AsyncState;
    //在原始套接字上調(diào)用EndAccept方法,返回新的套接字
    Socket service = MyServer.EndAccept(iar);
}

至此音榜,服務(wù)器端已經(jīng)準(zhǔn)備好了庞瘸。客戶端應(yīng)通過BeginConnect方法和EndConnect來遠(yuǎn)程連接主機(jī)赠叼。在調(diào)用BeginConnect方法時(shí)必須注冊相應(yīng)的回調(diào)函數(shù)并且至少傳遞一個(gè)Socket的實(shí)例給state參數(shù)擦囊,以保證EndConnect方法中能使用原始的套接字。下面是一段是BeginConnect的調(diào)用:

Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp)
IPAddress ip=IPAddress.Parse("127.0.0.1");
IPEndPoint iep=new IPEndPoint(ip,13000);
socket.BeginConnect(iep, new AsyncCallback(Connect),socket);

EndConnect是一種阻塞方法嘴办,用于完成BeginConnect方法的異步連接誒遠(yuǎn)程主機(jī)的請求瞬场。在注冊了回調(diào)函數(shù)后必須接收BeginConnect方法返回的IASynccReuslt作為參數(shù)。下面為代碼演示:

void Connect(IAsyncResult iar)
{
    Socket client=(Socket)iar.AsyncState;
    try
    {
        client.EndConnect(iar);
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
    }
    finally
    {

    }
}

除了采用上述方法建立連接之后涧郊,也可以采用TcpListener類里面的方法進(jìn)行連接建立贯被。下面是服務(wù)器端對關(guān)于TcpListener類使用BeginAccetpTcpClient方法處理一個(gè)傳入的連接嘗試。以下是使用BeginAccetpTcpClient方法和EndAccetpTcpClient方法的代碼:

public static void DoBeginAccept(TcpListener listner)
{
    //開始從客戶端監(jiān)聽連接
    Console.WriteLine("Waitting for a connection");
    //接收連接
    //開始準(zhǔn)備接入新的連接妆艘,一旦有新連接嘗試則調(diào)用回調(diào)函數(shù)DoAcceptTcpCliet
    listner.BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpCliet), listner);
}

//處理客戶端的連接
public static void DoAcceptTcpCliet(IAsyncResult iar)
{
    //還原原始的TcpListner對象
    TcpListener listener = (TcpListener)iar.AsyncState;

    //完成連接的動(dòng)作彤灶,并返回新的TcpClient
    TcpClient client = listener.EndAcceptTcpClient(iar);
    Console.WriteLine("連接成功");
}

代碼的處理邏輯為:
(1)調(diào)用BeginAccetpTcpClient方法開開始連接新的連接,當(dāng)連接視圖發(fā)生時(shí)双仍,回調(diào)函數(shù)被調(diào)用以完成連接操作枢希;
(2)上面DoAcceptTcpCliet方法通過AsyncState屬性獲得由BeginAcceptTcpClient傳入的listner實(shí)例;
(3)在得到listener對象后朱沃,用它調(diào)用EndAcceptTcpClient方法,該方法返回新的包含客戶端信息的TcpClient。

BeginConnect方法和EndConnect方法可用于客戶端嘗試建立與服務(wù)端的連接逗物,這里和第一種方法并無區(qū)別搬卒。下面看實(shí)例:

public void doBeginConnect(IAsyncResult iar)
{
    Socket client=(Socket)iar.AsyncState;
    //開始與遠(yuǎn)程主機(jī)進(jìn)行連接
    client.BeginConnect(serverIP[0],13000,requestCallBack,client);
    Console.WriteLine("開始與服務(wù)器進(jìn)行連接");
}
private void requestCallBack(IAsyncResult iar)
{
    try
    {
        //還原原始的TcpClient對象
        TcpClient client=(TcpClient)iar.AsyncState;
        //
        client.EndConnect(iar);
        Console.WriteLine("與服務(wù)器{0}連接成功",client.Client.RemoteEndPoint);
    }
    catch(Exception e)
    {
        Console.WriteLine(e.ToString());
    }
    finally
    {

    }
}

以上是建立連接的兩種方法◆嶙浚可根據(jù)需要選擇使用契邀。

3.2 發(fā)送與接受數(shù)據(jù)
  在建立了套接字的連接后,就可以服務(wù)器端和客戶端之間進(jìn)行數(shù)據(jù)通信了失暴。異步套接字用BeginSend和EndSend方法來負(fù)責(zé)數(shù)據(jù)的發(fā)送坯门。注意在調(diào)用BeginSend方法前要確保雙方都已經(jīng)建立連接,否則會(huì)出異常逗扒。下面演示代碼:

private static void Send(Socket handler, String data)
{
    // Convert the string data to byte data using ASCII encoding.     
    byte[] byteData = Encoding.ASCII.GetBytes(data);
    // Begin sending the data to the remote device.     
    handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler);
}
private static void SendCallback(IAsyncResult ar)
{
    try
    {
        // Retrieve the socket from the state object.     
        Socket handler = (Socket)ar.AsyncState;
        // Complete sending the data to the remote device.     
        int bytesSent = handler.EndSend(ar);
        Console.WriteLine("Sent {0} bytes to client.", bytesSent);
        handler.Shutdown(SocketShutdown.Both);
        handler.Close();
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
    }
}

接收數(shù)據(jù)是通過BeginReceive和EndReceive方法:

private static void Receive(Socket client)
{
    try
    {
        // Create the state object.     
        StateObject state = new StateObject();
        state.workSocket = client;
        // Begin receiving the data from the remote device.     
        client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
    }
}
private static void ReceiveCallback(IAsyncResult ar)
{
    try
    {
        // Retrieve the state object and the client socket     
        // from the asynchronous state object.     
        StateObject state = (StateObject)ar.AsyncState;
        Socket client = state.workSocket;
        // Read data from the remote device.     
        int bytesRead = client.EndReceive(ar);
        if (bytesRead > 0)
        {
            // There might be more data, so store the data received so far.     

            state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
            // Get the rest of the data.     
            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
        }
        else
        {
            // All the data has arrived; put it in response.     
            if (state.sb.Length > 1)
            {
                response = state.sb.ToString();
            }
            // Signal that all bytes have been received.     
            receiveDone.Set();
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
    }
}

上述代碼的處理邏輯為:

(1)首先處理連接的回調(diào)函數(shù)里得到的通訊套接字client古戴,接著開始接收數(shù)據(jù);
(2)當(dāng)數(shù)據(jù)發(fā)送到緩沖區(qū)中矩肩,BeginReceive方法試圖從buffer數(shù)組中讀取長度為buffer.length的數(shù)據(jù)塊现恼,并返回接收到的數(shù)據(jù)量bytesRead。最后接收并打印數(shù)據(jù)黍檩。

除了上述方法外叉袍,還可以使用基于NetworkStream相關(guān)的異步發(fā)送和接收方法,下面是基于NetworkStream相關(guān)的異步發(fā)送和接收方法的使用介紹刽酱。
  NetworkStream使用BeginRead和EndRead方法進(jìn)行讀操作喳逛,使用BeginWreite和EndWrete方法進(jìn)行寫操作,下面看實(shí)例:

static void DataHandle(TcpClient client)
{
  TcpClient tcpClient = client;
  //使用TcpClient的GetStream方法獲取網(wǎng)絡(luò)流
  NetworkStream ns = tcpClient.GetStream();
  //檢查網(wǎng)絡(luò)流是否可讀
  if(ns.CanRead)
  {
    //定義緩沖區(qū)
    byte[] read = new byte[1024];
    ns.BeginRead(read,0,read.Length,new AsyncCallback(myReadCallBack),ns);  
  }
  else
  {
    Console.WriteLine("無法從網(wǎng)絡(luò)中讀取流數(shù)據(jù)");
  }
}

public static void myReadCallBack(IAsyncResult iar)
{
    NetworkStream ns = (NetworkStream)iar.AsyncState;
    byte[] read = new byte[1024];
    String data = "";
    int recv;

    recv = ns.EndRead(iar);
    data = String.Concat(data, Encoding.ASCII.GetString(read, 0, recv));

    //接收到的消息長度可能大于緩沖區(qū)總大小棵里,反復(fù)循環(huán)直到讀完為止
    while (ns.DataAvailable)
    {
        ns.BeginRead(read, 0, read.Length, new AsyncCallback(myReadCallBack), ns);
    }
    //打印
    Console.WriteLine("您收到的信息是" + data);
}

3.3 程序阻塞與異步中的同步問題
  .Net里提供了EventWaitHandle類來表示一個(gè)線程的同步事件艺配。EventWaitHandle即事件等待句柄,他允許線程通過操作系統(tǒng)互發(fā)信號和等待彼此的信號來達(dá)到線程同步的目的衍慎。這個(gè)類有2個(gè)子類转唉,分別為AutoRestEevnt(自動(dòng)重置)和ManualRestEvent(手動(dòng)重置)。下面是線程同步的幾個(gè)方法:
(1)Rset方法:將事件狀態(tài)設(shè)為非終止?fàn)顟B(tài)稳捆,導(dǎo)致線程阻塞赠法。這里的線程阻塞是指允許其他需要等待的線程進(jìn)行阻塞即讓含WaitOne()方法的線程阻塞;
(2)Set方法:將事件狀態(tài)設(shè)為終止?fàn)顟B(tài)乔夯,允許一個(gè)或多個(gè)等待線程繼續(xù)砖织。該方法發(fā)送一個(gè)信號給操作系統(tǒng),讓處于等待的某個(gè)線程從阻塞狀態(tài)轉(zhuǎn)換為繼續(xù)運(yùn)行末荐,即WaitOne方法的線程不在阻塞侧纯;
(3)WaitOne方法:阻塞當(dāng)前線程,直到當(dāng)前的等待句柄收到信號甲脏。此方法將一直使本線程處于阻塞狀態(tài)直到收到信號為止眶熬,即當(dāng)其他非阻塞進(jìn)程調(diào)用set方法時(shí)可以繼續(xù)執(zhí)行妹笆。

public static void StartListening()
{
    // Data buffer for incoming data.     
    byte[] bytes = new Byte[1024];
    // Establish the local endpoint for the socket.     
    // The DNS name of the computer     
    // running the listener is "host.contoso.com".     
    //IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
    //IPAddress ipAddress = ipHostInfo.AddressList[0];
    IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
    IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
    // Create a TCP/IP socket.     
    Socket listener = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
    // Bind the socket to the local     
    //endpoint and listen for incoming connections.     
    try
    {
        listener.Bind(localEndPoint);
        listener.Listen(100);
        while (true)
        {
            // Set the event to nonsignaled state.     
            allDone.Reset();
            // Start an asynchronous socket to listen for connections.     
            Console.WriteLine("Waiting for a connection...");
            listener.BeginAccept(new AsyncCallback(AcceptCallback),listener);
            // Wait until a connection is made before continuing.     
            allDone.WaitOne();
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
    }
    Console.WriteLine("\nPress ENTER to continue...");
    Console.Read();
}

上述代碼的邏輯為:

(1)試用了ManualRestEvent對象創(chuàng)建一個(gè)等待句柄,在調(diào)用BeginAccept方法前使用Rest方法允許其他線程阻塞娜氏;
(2)為了防止在連接完成之前對套接字進(jìn)行讀寫操作拳缠,務(wù)必要在BeginAccept方法后調(diào)用WaitOne來讓線程進(jìn)入阻塞狀態(tài)。

當(dāng)有連接接入后系統(tǒng)會(huì)自動(dòng)調(diào)用會(huì)調(diào)用回調(diào)函數(shù)贸弥,所以當(dāng)代碼執(zhí)行到回調(diào)函數(shù)時(shí)說明連接已經(jīng)成功窟坐,并在函數(shù)的第一句就調(diào)用Set方法讓處于等待的線程可以繼續(xù)執(zhí)行。

四绵疲、實(shí)例
  下面是一個(gè)實(shí)例哲鸳,客戶端請求連接,服務(wù)器端偵聽端口盔憨,當(dāng)連接建立之后徙菠,服務(wù)器發(fā)送字符串給客戶端,客戶端收到后并回發(fā)給服務(wù)器端般渡。

服務(wù)器端代碼:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
// State object for reading client data asynchronously     
public class StateObject
{
    // Client socket.     
    public Socket workSocket = null;
    // Size of receive buffer.     
    public const int BufferSize = 1024;
    // Receive buffer.     
    public byte[] buffer = new byte[BufferSize];
    // Received data string.     
    public StringBuilder sb = new StringBuilder();
}
public class AsynchronousSocketListener
{
    // Thread signal.     
    public static ManualResetEvent allDone = new ManualResetEvent(false);
    public AsynchronousSocketListener()
    {
    }
    public static void StartListening()
    {
        // Data buffer for incoming data.     
        byte[] bytes = new Byte[1024];
        // Establish the local endpoint for the socket.     
        // The DNS name of the computer     
        // running the listener is "host.contoso.com".     
        //IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
        //IPAddress ipAddress = ipHostInfo.AddressList[0];
        IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
        IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
        // Create a TCP/IP socket.     
        Socket listener = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
        // Bind the socket to the local     
        //endpoint and listen for incoming connections.     
        try
        {
            listener.Bind(localEndPoint);
            listener.Listen(100);
            while (true)
            {
                // Set the event to nonsignaled state.     
                allDone.Reset();
                // Start an asynchronous socket to listen for connections.     
                Console.WriteLine("Waiting for a connection...");
                listener.BeginAccept(new AsyncCallback(AcceptCallback),listener);
                // Wait until a connection is made before continuing.     
                allDone.WaitOne();
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
        Console.WriteLine("\nPress ENTER to continue...");
        Console.Read();
    }
    public static void AcceptCallback(IAsyncResult ar)
    {
        // Signal the main thread to continue.     
        allDone.Set();
        // Get the socket that handles the client request.     
        Socket listener = (Socket)ar.AsyncState;
        Socket handler = listener.EndAccept(ar);
        // Create the state object.     
        StateObject state = new StateObject();
        state.workSocket = handler;
        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
    }
    public static void ReadCallback(IAsyncResult ar)
    {
        String content = String.Empty;
        // Retrieve the state object and the handler socket     
        // from the asynchronous state object.     
        StateObject state = (StateObject)ar.AsyncState;
        Socket handler = state.workSocket;
        // Read data from the client socket.     
        int bytesRead = handler.EndReceive(ar);
        if (bytesRead > 0)
        {
            // There might be more data, so store the data received so far.     
            state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
            // Check for end-of-file tag. If it is not there, read     
            // more data.     
            content = state.sb.ToString();
            if (content.IndexOf("<EOF>") > -1)
            {
                // All the data has been read from the     
                // client. Display it on the console.     
                Console.WriteLine("Read {0} bytes from socket. \n Data : {1}", content.Length, content);
                // Echo the data back to the client.     
                Send(handler, content);
            }
            else
            {
                // Not all data received. Get more.     
                handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
            }
        }
    }
    private static void Send(Socket handler, String data)
    {
        // Convert the string data to byte data using ASCII encoding.     
        byte[] byteData = Encoding.ASCII.GetBytes(data);
        // Begin sending the data to the remote device.     
        handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler);
    }
    private static void SendCallback(IAsyncResult ar)
    {
        try
        {
            // Retrieve the socket from the state object.     
            Socket handler = (Socket)ar.AsyncState;
            // Complete sending the data to the remote device.     
            int bytesSent = handler.EndSend(ar);
            Console.WriteLine("Sent {0} bytes to client.", bytesSent);
            handler.Shutdown(SocketShutdown.Both);
            handler.Close();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }
    public static int Main(String[] args)
    {
        StartListening();
        return 0;
    }
}

客戶端代碼:

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;
// State object for receiving data from remote device.     
public class StateObject
{
    // Client socket.     
    public Socket workSocket = null;
    // Size of receive buffer.     
    public const int BufferSize = 256;
    // Receive buffer.     
    public byte[] buffer = new byte[BufferSize];
    // Received data string.     
    public StringBuilder sb = new StringBuilder();
}
public class AsynchronousClient
{
    // The port number for the remote device.     
    private const int port = 11000;
    // ManualResetEvent instances signal completion.     
    private static ManualResetEvent connectDone = new ManualResetEvent(false);
    private static ManualResetEvent sendDone = new ManualResetEvent(false);
    private static ManualResetEvent receiveDone = new ManualResetEvent(false);
    // The response from the remote device.     
    private static String response = String.Empty;
    private static void StartClient()
    {
        // Connect to a remote device.     
        try
        {
            // Establish the remote endpoint for the socket.     
            // The name of the     
            // remote device is "host.contoso.com".     
            //IPHostEntry ipHostInfo = Dns.Resolve("user");
            //IPAddress ipAddress = ipHostInfo.AddressList[0];
            IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
            IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
            // Create a TCP/IP socket.     
            Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            // Connect to the remote endpoint.     
            client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
            connectDone.WaitOne();
            // Send test data to the remote device.     
            Send(client, "This is a test<EOF>");
            sendDone.WaitOne();
            // Receive the response from the remote device.     
            Receive(client);
            receiveDone.WaitOne();
            // Write the response to the console.     
            Console.WriteLine("Response received : {0}", response);
            // Release the socket.     
            client.Shutdown(SocketShutdown.Both);
            client.Close();
            Console.ReadLine();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }
    private static void ConnectCallback(IAsyncResult ar)
    {
        try
        {
            // Retrieve the socket from the state object.     
            Socket client = (Socket)ar.AsyncState;
            // Complete the connection.     
            client.EndConnect(ar);
            Console.WriteLine("Socket connected to {0}", client.RemoteEndPoint.ToString());
            // Signal that the connection has been made.     
            connectDone.Set();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }
    private static void Receive(Socket client)
    {
        try
        {
            // Create the state object.     
            StateObject state = new StateObject();
            state.workSocket = client;
            // Begin receiving the data from the remote device.     
            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }
    private static void ReceiveCallback(IAsyncResult ar)
    {
        try
        {
            // Retrieve the state object and the client socket     
            // from the asynchronous state object.     
            StateObject state = (StateObject)ar.AsyncState;
            Socket client = state.workSocket;
            // Read data from the remote device.     
            int bytesRead = client.EndReceive(ar);
            if (bytesRead > 0)
            {
                // There might be more data, so store the data received so far.     

                state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
                // Get the rest of the data.     
                client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
            }
            else
            {
                // All the data has arrived; put it in response.     
                if (state.sb.Length > 1)
                {
                    response = state.sb.ToString();
                }
                // Signal that all bytes have been received.     
                receiveDone.Set();
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }
    private static void Send(Socket client, String data)
    {
        // Convert the string data to byte data using ASCII encoding.     
        byte[] byteData = Encoding.ASCII.GetBytes(data);
        // Begin sending the data to the remote device.     
        client.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), client);
    }
    private static void SendCallback(IAsyncResult ar)
    {
        try
        {
            // Retrieve the socket from the state object.     
            Socket client = (Socket)ar.AsyncState;
            // Complete sending the data to the remote device.     
            int bytesSent = client.EndSend(ar);
            Console.WriteLine("Sent {0} bytes to server.", bytesSent);
            // Signal that all bytes have been sent.     
            sendDone.Set();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }
    public static int Main(String[] args)
    {
        StartClient();
        return 0;
    }
}

轉(zhuǎn)自:http://www.cnblogs.com/sunev/archive/2012/08/07/2625688.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末懒豹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子驯用,更是在濱河造成了極大的恐慌脸秽,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蝴乔,死亡現(xiàn)場離奇詭異记餐,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)薇正,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門片酝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人挖腰,你說我怎么就攤上這事雕沿。” “怎么了猴仑?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵审轮,是天一觀的道長。 經(jīng)常有香客問我辽俗,道長疾渣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任崖飘,我火速辦了婚禮榴捡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘朱浴。我一直安慰自己吊圾,他們只是感情好达椰,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著街夭,像睡著了一般砰碴。 火紅的嫁衣襯著肌膚如雪躏筏。 梳的紋絲不亂的頭發(fā)上板丽,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天,我揣著相機(jī)與錄音趁尼,去河邊找鬼埃碱。 笑死,一個(gè)胖子當(dāng)著我的面吹牛酥泞,可吹牛的內(nèi)容都是我干的砚殿。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼芝囤,長吁一口氣:“原來是場噩夢啊……” “哼似炎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起悯姊,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤羡藐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后悯许,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體仆嗦,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年先壕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瘩扼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,090評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡垃僚,死狀恐怖集绰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情谆棺,我是刑警寧澤栽燕,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站包券,受9級特大地震影響纫谅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜溅固,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一付秕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧侍郭,春花似錦询吴、人聲如沸掠河。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽唠摹。三九已至,卻和暖如春奉瘤,著一層夾襖步出監(jiān)牢的瞬間勾拉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工盗温, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留藕赞,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓卖局,卻偏偏與公主長得像斧蜕,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子砚偶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容