C# Asynchronous Socket Communication

0. Based on the Socket (synchronous) communication of c# in the previous article, after several great comments, I found that there are many deficiencies, so I wrote an improved version of asynchronous socket communication based on c#. To deepen the use and understanding of Socket. The client and server both use the WPF interface, which realizes the functions of heartbeat, disconnection and reconnection, and one server corresponds to multiple clients.

1. Server

1.1 First create a Socket instance and bind it to the port number 20000; start listening through the Listen method and set the maximum number of listening.

// Create a new Socket server instance and bind it to port 20000 
this .socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 this .socketServer.Bind( new IPEndPoint(IPAddress.Any, 20000 ) );

// Set the maximum number of listeners 
this .socketServer.Listen( 10 );

1.2 Start to monitor the client asynchronously. BeginAccept and EndAccept are used. When there is a client connection, the callback function will be called automatically. At this time, the heartbeat will start and the client's Socket and heartbeat information will be added to the global dictionary.

this.socketServer.BeginAccept(ar =>
{
    Socket _socket = socketServer.EndAccept (ar);

    //心跳 心跳
    System.Timers.Timer heartbeatTimer = new System.Timers.Timer ();
    heartbeatTimer.Interval = 600000;
    heartbeatTimer.Elapsed += new System.Timers.ElapsedEventHandler((s, e) => heartbeatTimerIsUp(s, e, _socket));
    heartbeatTimer.Start();

    SocketInfo info = new SocketInfo();
    info.heartbeatTimer = heartbeatTimer;
    this.socketInfoDic.Add(_socket, info);

    // Start receiving data 
    thdRevMethod(_socket);
     // Start next listening 
    ListenSocket();
}, null);

1.3 Receive data, when the client connects successfully in the previous step, you can start asynchronously receiving data from the client; BeginReceive and EndReceive are used, and the callback function will be automatically called after receiving the data from the client. Since the size of the received data is uncertain, 1024 bytes are received here each time, and then the received data is spliced ​​together, and the Available attribute is used, which is the number of bytes that can be read. If it is less than or equal to 0, it indicates that this time Data is received.

Socket _socket = obj as Socket;
if (this.socketInfoDic.ContainsKey(_socket))
{
    SocketInfo socketInfo = socketInfoDic[_socket];
     // Start receiving messages 
    _socket.BeginReceive(socketInfo.tempByte, 0 , socketInfo.tempByte.Length, SocketFlags.None, ar =>
    {
        try
        {
            int resInt = _socket.EndReceive (ar);
            socketInfo.contentByte = socketInfo.contentByte.Concat(socketInfo.tempByte).ToArray();
            socketInfo.tempByte = new byte[1024];
            if (_socket.Available <= 0)
            {
                int actualLength = socketInfo.contentByte.Length - (socketInfo.tempByte.Length - resInt);
                string res = Encoding.Default.GetString(socketInfo.contentByte, 0, actualLength);
                socketInfo.contentByte = new byte[0];
            }
            thdRevMethod(_socket);
        }
        catch (SocketException sex)
        {
            if (sex.SocketErrorCode == SocketError.ConnectionReset)
            {
            // When the client disconnects, remove the client from the list 
            if ( this .socketInfoDic.ContainsKey(_socket))
                {
                    this.socketInfoDic.Remove(_socket);
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show( " Program exception: " + ex);
        }
    }, null);
}

1.4 When sending data, BeginSend and EndSend are used. After successful sending, the callback function will be called automatically. The EndSend() method returns the number of bytes sent successfully.

byte[] byteStr = Encoding.Default.GetBytes(msg);
_socket.BeginSend(byteStr, 0, byteStr.Length, SocketFlags.None, ar =>
{
    _socket.EndSend(ar);
}, null);

2. Client

2.1 Create a new Socket instance and start asynchronously connecting to the server. BeginConnect and EndConnect are used. If the connection is successful, the callback function will be automatically called. At this time, the heartbeat can be started and the data can be received and sent.

// Create a new client instance and connect to the port number where the server is located 
this .socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

// Connect to the server 
this .socketClient.BeginConnect( " 127.0.0.1 " , 20000 , ar =>
{
    try
    {
        this.socketClient.EndConnect(ar);
        this.thdRevMethod();
    }
    catch (SocketException sex)
    {
        if (sex.SocketErrorCode == SocketError.ConnectionRefused)
        {
            this.reconnectTimer.Start();
            this.heartbeatTimer.Stop();
        }
    }
    catch (Exception)
    {
        this.heartbeatTimer.Stop();
        throw;
    }
}, null);

2.2 Sending and receiving data (similar to the client)

3. Running the example

4. Summary

If there are any problems in the above description or in the code logic, I hope you can help point it out, thank you!

The points to note are as follows:

4.1. When receiving data asynchronously, because the size of the received data is uncertain, it is tentatively scheduled to receive only 1024 bytes at a time. According to the judgment of Available, if the received data is larger than 1024 bytes, it will be obtained by splicing in sequence. data.

4.2 In the server, the byte[] of 1024 bytes received each time cannot be defined as a global variable, but needs to be in one-to-one correspondence with each Socket client, otherwise an error will occur when receiving messages from multiple clients. (This is what I understand here)

The source code download address is as follows: AsyncSocketDemo.rar

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324609891&siteId=291194637