C#异步socket通信
我们在开发网络通信软件的时候,都需要实现异步的通信,有效的提高通信效率,下面来介绍下C#中异步socket通信的实现方式。
服务器端处理方式
首先定义一个用于函数回调传递的参数实体类:
1
2
3
4
5
6
7
8
9
10
11
|
public class StateObject
{
// 保存的socket连接
public Socket workSocket = null;
// 接收的数据大小
public const int BufferSize = 1024;
// 接收的数据缓冲区
public byte[] buffer = new byte[BufferSize];
// 其他一些自定义数据字段
public int num;
}
|
获取本地网络IP地址:
1
2
3
4
5
6
7
8
9
10
|
string name = Dns.GetHostName();
IPAddress[] ipadrlist = Dns.GetHostAddresses(name);
foreach (IPAddress ipa in ipadrlist)
{
if (ipa.AddressFamily == AddressFamily.InterNetwork)
{
ServerIP1.Text = ipa.ToString();
break;
}
}
|
接收到消息后使用委托函数更新UI界面,避免出现跨线程调用UI控件时的错误:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
/// <summary>
/// 更新界面状态信息委托回调事件
/// </summary>
/// <param name="str"></param>
public delegate void ShowStatusCallBack(String str);
/// <summary>
/// 更新界面状态信息
/// </summary>
/// <param name="str"></param>
public void ShowStatus(string str)
{
if (this.InvokeRequired)
{
ShowStatusCallBack d = new ShowStatusCallBack(ShowStatus);
this.Invoke(d, new object[] { str });
}
else
{
textBoxMessage.Text += str + "\r\n";
textBoxMessage.SelectionStart = textBoxMessage.Text.Length;
textBoxMessage.ScrollToCaret();
if(textBoxMessage.Text.Length > 10000)
{
textBoxMessage.Clear();
}
}
}
|
开启socket服务器,异步监听客户端连接,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public void StartServer(int num, string ip, string port)
{
IPAddress address = IPAddress.Parse(ip.Trim());
int portNum = int.Parse(port.Trim());
IPEndPoint endPoint = new IPEndPoint(address, portNum);
try
{
// 创建负责监听的套接字,注意其中的参数;
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(endPoint);
// 设置监听队列的长度;
listener.Listen(10);
StateObject stateObject = new StateObject();
stateObject.workSocket = listener;
stateObject.num = num;
// Set the event to nonsignaled state.
listener.BeginAccept(new AsyncCallback(AcceptCallback), stateObject);
textBoxMessage.Text += "服务器" + num.ToString() + "已开启,等待连接。。。。。\r\n";
}
catch (Exception ex)
{
ShowStatus(ex.Message);
}
}
|
客户端连接异步回调函数,保存连接成功的客户端socket句柄,开启异步监听接收客户端的数据发送,并且继续监听等待新的客户端连接,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
public void AcceptCallback(IAsyncResult ar)
{
try
{
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket.EndAccept(ar);
IPEndPoint remoteEndPoint;
remoteEndPoint = (IPEndPoint)client.RemoteEndPoint;
ShowStatus("客户端已连接!" + remoteEndPoint.Address.ToString() + ":" + remoteEndPoint.Port.ToString());
StateObject clientState = new StateObject();
clientState.num = state.num;
clientState.workSocket = client;
client.BeginReceive(clientState.buffer, 0, clientState.buffer.Length, 0, new AsyncCallback(ReadCallback), clientState);
switch (state.num)
{
//自定义处理
}
//继续监听客户端连接
state.workSocket.BeginAccept(new AsyncCallback(AcceptCallback), state);
}
catch (Exception ex)
{
ShowStatus(ex.Message);
}
}
|
异步接收数据回调函数,接收完毕数据后,继续开启等待接收新的数据:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public void ReadCallback(IAsyncResult ar)
{
try
{
StateObject state = (StateObject)ar.AsyncState;
// Read data from the client socket.
int bytesRead = state.workSocket.EndReceive(ar);
if (bytesRead > 0)
{
content = ByteToString(state.buffer, bytesRead);
ShowStatus("服务器--" + state.num + "-- " + content);
//转发
Send(state, bytesRead);
Array.Clear(state.buffer, 0, state.buffer.Length);
state.workSocket.BeginReceive(state.buffer, 0, state.buffer.Length, 0, new AsyncCallback(ReadCallback), state);
}
} catch (Exception ex)
{
ShowStatus(ex.Message);
}
}
|
发送数据,同样使用异步回调函数来确保数据发送完毕,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
socket.BeginSend(stateObject.buffer, 0, byteRead, 0, new AsyncCallback(SendCallback), socket);
private 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);
ShowStatus("已发送数据大小:" + bytesSent.ToString());
}
catch (Exception e)
{
ShowStatus(e.Message);
}
}
|
客户端连接服务器
客户端连接服务器,同样使用连接回调方式来连接服务器:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
public void ConnectServer(int num, string ip,string port)
{
try
{
IPAddress ipAddress = IPAddress.Parse(ip);
IPEndPoint remoteEP = new IPEndPoint(ipAddress, int.Parse(port));
// Create a TCP/IP socket.
Socket socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
StateObject stateObject = new StateObject();
stateObject.num = num;
stateObject.workSocket = socketClient;
// Connect to the remote endpoint.
socketClient.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), stateObject);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
StateObject stateObject = (StateObject)ar.AsyncState;
// Retrieve the socket from the state object.
//Socket client = (Socket)ar.AsyncState;
// Complete the connection.
stateObject.workSocket.EndConnect(ar);
ShowStatus("已连接服务器。。。。\r\n");
stateObject.workSocket.BeginReceive(stateObject.buffer, 0, stateObject.buffer.Length, 0, new AsyncCallback(ReadCallback), stateObject);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
|
运行示例如图所示: