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

原创 2016年11月17日 18:47:03

异步编写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[] byteData = 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同步通信的基础上,分析和研究Socket异步编程的实现方法,目的是深入了解Socket编程的基本原理,增强对网络游戏开发相关内容的认识。什么是Socket编程的异步是实现所谓...
  • qinyuanpei
  • qinyuanpei
  • 2015年03月23日 21:36
  • 5887

C#中Socket通信编程的异步实现

本文将在C#中Socket同步通信的基础上,分析和研究Socket异步编程的实现方法,目的是深入了解Socket编程的基本原理,增强对网络游戏开发相关内容的认识。 什么是Socket编程的异步是实现 ...
  • mss359681091
  • mss359681091
  • 2016年06月30日 15:49
  • 15663

异步 (非阻塞) 客户端 Socket 封装类(无需MFC)

[图片] 示例程序截图 [代码] 使用方法 view source print? 01 #include "XSocket.h" ...
  • cuiyifang
  • cuiyifang
  • 2012年09月23日 13:20
  • 1050

异步Socket通信

异步Socket通信By John McTainsh  From: http://www.codeproject.com/csharp/socketsincs.aspTranslate by: Hil...
  • hillfree
  • hillfree
  • 2002年09月25日 10:33
  • 7321

C#网络编程系列文章(一)之Socket实现异步TCP服务器

原创性声明 开篇 本人因为对于网络编程的喜爱,经常性的使用c#编写各类服务器(e.g TCP服务器,UDP服务器),但是基本上都是搞着玩,网上也有很多讲c#网络编程的文章,当然我也参考了很多作者写...
  • zhujunxxxxx
  • zhujunxxxxx
  • 2015年03月14日 13:43
  • 18124

C#实现Socket编程 (异步通讯,解决Tcp粘包)第三阶段

  • 2015年07月16日 14:05
  • 155KB
  • 下载

一个简单的socket客户端和服务端的例子

网络编程中最基础的就是socket的操作,这里记录一下socket的基础操作有哪些,分别是什么作用,最后以一个简单的客户端和服务端例子收尾。 socket是什么? socket起源于Unix,秉承...
  • u011408355
  • u011408355
  • 2015年08月01日 14:19
  • 6042

Socket异步发送接收,Windows

vdAsynSocket.h: //////////////////////////////////////////////////////////////// // //Descript:...
  • kanguolaikanguolaik
  • kanguolaikanguolaik
  • 2013年05月23日 09:46
  • 963

c#异步Socket Tcp服务器实现

原创性申明 本文作者: 小竹zz  本文地址:http://blog.csdn.net/zhujunxxxxx 转载请注明出处。 介绍 在c#中微软已经提供了TcpListener和TcpClient...
  • zhujunxxxxx
  • zhujunxxxxx
  • 2015年02月06日 21:31
  • 6005

C#:简单的Socket异步通信服务

Socket 请参考此链接来获取对于Socket的认识:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.aspx ...
  • jsjpanxiaoyu
  • jsjpanxiaoyu
  • 2016年10月28日 13:02
  • 571
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C# Socket编程 服务端与客户端(三) 异步客户端
举报原因:
原因补充:

(最多只允许输入30个字)