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客户端详细代码:
执行结果:
参考:MSDN的Socket类
需要注意的点:
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类
相关文章推荐
- C# socket编程 异步服务端 同步客户端(转)
- C# socket编程 异步服务端 同步客户端
- c# Socket 异步客户端服务端
- C# Socket编程 服务端与客户端(一)
- 最基本的Socket编程(服务端跟客户端通信) C#版
- C#Socket编程多客户端基于同一服务端通信
- 基于C#的socket编程的TCP异步实现 ,包含服务器端与客户端源代码
- C# Socket编程 服务端与客户端(二)
- c# WINFORM SOCKET编程-简单聊天程序(客户端)
- C#中使用异步Socket编程实现TCP网络服务的C/S的通讯构架(二)
- 在C#中使用异步Socket编程实现TCP网络服务的C/S的通讯构架(一)----基础类库部分
- C#异步Socket编程
- 在C#中使用异步Socket编程实现TCP网络服务的C/S的通讯构架(二)----使用方法
- 在C#中使用异步Socket编程实现TCP网络服务的C/S的通讯构架
- 在C#中使用异步Socket编程实现TCP网络服务的C/S的通讯构架(一)----基础类库部分(来源:http://blog.csdn.net/yangjundeng/archive/2005/03/17/321920.aspx)
- 在C#中使用异步Socket编程实现TCP网络服务的C/S的通讯构架(二)----使用方法
- 在C#中使用异步Socket编程实现TCP网络服务的C/S的通讯构架(一)----基础类库部分
- [转]在C#中使用异步Socket编程实现TCP网络服务的C/S的通讯构架(一)
- c# WINFORM SOCKET编程-简单聊天程序(服务端)(转载)
- 在C#中使用异步Socket编程实现TCP网络服务的C/S的通讯构架(一)----基础类库部分