您的位置:首页 > 编程语言 > C#

C# Socket编程 服务端与客户端(三) 异步客户端

2016-11-17 18:47 316 查看
异步编写Socket客户端,我不再使用Connect与Send,而使用了BeginConnect与EndConnect、BeginSend与EndSend,将具体的操作放到了Begin时指定的回调函数里。

需要注意的点:

1.程序在Begin后直接返回,以BeginConnect为例,在服务端确定连接时才调用指定的ConnectCallBack函数。

2.在每个Begin指定的回调函数里,总是需要有一个对应的End操作,在End操作之后,才是真正得完成了对应的操作,每个Begin只能被End一次。

3.用到了ManualResetEvent对象。MSDN上的解释是“通知一个或多个正在等待的线程已发生事件”,我的理解是一个用于多个线程之间同步用的信号对象。Reset()让接下来的代码运行到WaitOne()时暂停,直到收到一个Set(),代码才会继续往下执行。在这里我们用它来同步代码,在BeginConnect处,只有连接成功后才继续往下执行,发送数据;在BeginSend处用来控制Send循环,当前一个Send完毕之后,才准备发下一个Send。当然我们可以调整Set在代码中的位置来控制什么时候继续Send。

4.用到了[ThreadStatic],这是一个将静态字段标记为线程静态的标记。静态字段默认是多线程共享的,在这里为了线程安全,我们使用了该标记,表明每个线程都独立拥有一个该静态字段。需要注意的是,静态字段在第一个线程处初始化,故我们在线程里初始化并通过传值解决了对象未初始化的问题。

异步Socket客户端详细代码:

class Program
{
[ThreadStatic]
private static ManualResetEvent connectWait;
[ThreadStatic]
private static ManualResetEvent sendWait;
static void Main(string[] args)
{
for (int i = 0; i < 1; i++)
{
new Thread(new ThreadStart(threadTest)).Start();
}
Console.ReadKey();
return;
}
private static void threadTest()
{
connectWait = new ManualResetEvent(false);
sendWait = new ManualResetEvent(false);
IPAddress localIP = Dns.GetHostAddresses(Dns.GetHostName())[1];
IPEndPoint ipEnd = new IPEndPoint(localIP, 3800);
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
manualResetObjecct clientObject = new manualResetObjecct();
clientObject.socket = clientSocket;
clientObject.connectWait = connectWait;
clientObject.sendWait = sendWait;
connectWait.Reset();
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}  BeginConnect...");
clientSocket.BeginConnect(ipEnd, new AsyncCallback(ConnectCallBack), clientObject);
connectWait.WaitOne();
for (int i = 0; i < 3; i++)
{
sendWait.Reset();
Send(clientObject, $"Thread NO:{Thread.CurrentThread.ManagedThreadId} SentenceNo:{i + 1} Hello world!");
sendWait.WaitOne();
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}  Data has been send to{clientSocket.RemoteEndPoint.ToString()}");
}
Console.WriteLine("press...");
Console.ReadKey();
for (int i = 0; i < 3; i++)
{
sendWait.Reset();
Send(clientObject, $"Thread NO:{Thread.CurrentThread.ManagedThreadId} SentenceNo:{i + 1} Hello world!");
sendWait.WaitOne();
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}  Data has been send to{clientSocket.RemoteEndPoint.ToString()}");
}
clientSocket.Close();
Console.WriteLine("closed!");
}
private static void ConnectCallBack(IAsyncResult clientObject)
{
manualResetObjecct manualObject = (manualResetObjecct)clientObject.AsyncState;
Socket clientSocket = manualObject.socket;
clientSocket.EndConnect(clientObject);
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}  Socket has connected to {clientSocket.RemoteEndPoint.ToString()}");
manualObject.connectWait.Set();
}
private static void Send(manualResetObjecct client, string data)
{
byte[] byteD
4000
ata = Encoding.UTF8.GetBytes(data);
string byteStr = string.Format("HEAD{0:000}", byteData.Length) + data;
byte[] packData = Encoding.UTF8.GetBytes(byteStr);
client.socket.BeginSend(packData, 0, packData.Length, SocketFlags.None, new AsyncCallback(SendCallBack), client);
}
private static void SendCallBack(IAsyncResult clientObject)
{
Socket clientSocket = ((manualResetObjecct)clientObject.AsyncState).socket;
int bytesCount = clientSocket.EndSend(clientObject);
((manualResetObjecct)clientObject.AsyncState).sendWait.Set();
}
}

internal class manualResetObjecct
{
internal ManualResetEvent connectWait = null;
internal ManualResetEvent sendWait = null;
internal Socket socket = null;
}

执行结果:

参考:MSDN的Socket类
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息