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

标签: 异步 通信 编程 socket
18402人阅读 评论(4) 收藏 举报
分类:

什么是Socket编程的异步是实现


所谓Socket编程的异步实现是指按照异步过程来实现Socket编程,那么什么是异步过程呢,我们把在完成了一次调用后通过状态、通知和回调来告知调用者的方式成为异步过程,换句话说,在异步过程中当调用一个方法时,调用者并不能够立刻得到结果,只有当这个方法调用完毕后调用者才能获得调用结果。这样做的好处是什么呢?答案是高效。相信大家还记得我们在《C#中Socket通信编程的同步实现》这篇文章中使用多线程来实现简单聊天的案例吧,在这个案例中我们需要开启两个线程来不断监听客户端的连接和客户端的消息,这样的效率肯定是很低的。那么现在好了,我们可以通过异步过程来解决这个问题,下面我们就来看看如何实现Socket的异步通信。


如何实现Socket异步通信


服务端


基本流程

  • 创建套接字
  • 绑定套接字的IP和端口号——Bind()
  • 使套接字处于监听状态等待客户端的连接请求——Listen()
  • 当请求到来后,使用BeginAccept()和EndAccept()方法接受请求,返回新的套接字
  • 使用BeginSend()/EndSend和BeginReceive()/EndReceive()两组方法与客户端进行收发通信
  • 返回,再次等待新的连接请求
  • 关闭套接字

代码示例

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace AsyncServer
{
    public class AsyncTCPServer
    {
        public void Start()
        {
            //创建套接字
            IPEndPoint ipe = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6065);
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //绑定端口和IP
            socket.Bind(ipe);
            //设置监听
            socket.Listen(10);
            //连接客户端
            AsyncAccept(socket);
        }

        /// <summary>
        /// 连接到客户端
        /// </summary>
        /// <param name="socket"></param>
        private void AsyncAccept(Socket socket)
        {
            socket.BeginAccept(asyncResult =>
            {
                //获取客户端套接字
                Socket client = socket.EndAccept(asyncResult);
                Console.WriteLine(string.Format("客户端{0}请求连接...", client.RemoteEndPoint));
                AsyncSend(client, "服务器收到连接请求");
                AsyncSend(client, string.Format("欢迎你{0}",client.RemoteEndPoint));
                AsyncReveive(client);
            }, null);
        }

        /// <summary>
        /// 接收消息
        /// </summary>
        /// <param name="client"></param>
        private void AsyncReveive(Socket socket)
        {
            byte[] data = new byte[1024];
            try
            {
                //开始接收消息
                socket.BeginReceive(data, 0, data.Length, SocketFlags.None,
                asyncResult =>
                {
                    int length = socket.EndReceive(asyncResult);
                    Console.WriteLine(string.Format("客户端发送消息:{0}", Encoding.UTF8.GetString(data)));
                }, null);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="client"></param>
        /// <param name="p"></param>
        private void AsyncSend(Socket client, string p)
        {
            if (client == null || p == string.Empty) return;
            //数据转码
            byte[] data = new byte[1024];
            data = Encoding.UTF8.GetBytes(p);
            try
            {
                //开始发送消息
                client.BeginSend(data, 0, data.Length, SocketFlags.None, asyncResult =>
                {
                    //完成消息发送
                    int length = client.EndSend(asyncResult);
                    //输出消息
                    Console.WriteLine(string.Format("服务器发出消息:{0}", p));
                }, null);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
    }
}



客户端


基本流程

  • 创建套接字并保证与服务器的端口一致
  • 使用BeginConnect()和EndConnect()这组方法向服务端发送连接请求
  • 使用BeginSend()/EndSend和BeginReceive()/EndReceive()两组方法与服务端进行收发通信
  • 关闭套接字

代码示例

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace AsyncClient
{
    public class AsyncTCPClient
    {
        /// <summary>
        /// 连接到服务器
        /// </summary>
        public void AsynConnect()
        {
            //端口及IP
            IPEndPoint ipe = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6065);
            //创建套接字
            Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //开始连接到服务器
            client.BeginConnect(ipe, asyncResult =>
            {
                client.EndConnect(asyncResult);
                //向服务器发送消息
                AsynSend(client,"你好我是客户端");
                AsynSend(client, "第一条消息");
                AsynSend(client, "第二条消息");
                //接受消息
                AsynRecive(client);
            }, null);
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="message"></param>
        public void AsynSend(Socket socket, string message)
        {
            if (socket == null || message == string.Empty) return;
            //编码
            byte[] data = Encoding.UTF8.GetBytes(message);
            try
            {
                socket.BeginSend(data, 0, data.Length, SocketFlags.None, asyncResult =>
                {
                    //完成发送消息
                    int length = socket.EndSend(asyncResult);
                    Console.WriteLine(string.Format("客户端发送消息:{0}", message));
                }, null);
            }
            catch (Exception ex)
            {
                Console.WriteLine("异常信息:{0}", ex.Message);
            }
        }

        /// <summary>
        /// 接收消息
        /// </summary>
        /// <param name="socket"></param>
        public void AsynRecive(Socket socket)
        {
            byte[] data = new byte[1024];
            try
            {
                //开始接收数据
                socket.BeginReceive(data, 0, data.Length, SocketFlags.None,
                asyncResult =>
                {
                    int length = socket.EndReceive(asyncResult);
                    Console.WriteLine(string.Format("收到服务器消息:{0}", Encoding.UTF8.GetString(data)));
                    AsynRecive(socket);
                }, null);
            }
            catch (Exception ex)
            {
                Console.WriteLine("异常信息:", ex.Message);
            }
        }
    }
}

从总体上来讲Socket异步编程的逻辑性更加明确了,因为我们只需要为每一个过程写好回调函数就好了。那么这个示例的效果如何呢?我们来看看它的演示效果:

Socket异步编程效果演示

总结


和Socket同步编程的案例相比,今天的这个案例可能只是对Socket异步编程内容的一个简单应用,因为博主到现在为止都还没有写出一个可以进行交互聊天的程序来。在Socket的异步编程中,服务端不需要为一个客户端单独创建一个线程来维护其连接,可是这样带来的一个问题就是博主不知道该如何实现一个多客户端的异步编程的实例。如果有朋友知道如何实现的话,还希望能够告诉我,毕竟学习就是一个相互促进的过程啊。好了,最后想说的是博主这段时间研究Socket异步编程中关于异步方法调用的写法问题。我们知道Socket异步编程中的方法是成对出现的,每一个方法都有一个回调函数,对于回调函数,这里有两种写法,以BeginConnect方法为例:


m_Socket.BeginConnect(this.m_ipEndPoint, 
        new AsyncCallback(this.ConnectCallBack), 
        this.m_Socket);//其中ConnectCallBack是一个回调函数
或者
m_Socket.BeginConnect(this.m_ipEndPoint,asyncResult=>
{
    //在这里添加更多代码
},null)


博主为什么要在这里说这两种写法呢,有两个原因:
* 第二种写法更为简洁,无需去构造容器传递Socket和消息,因为它们都是局部变量。如果我们使用第一种方法,因为主函数和回调函数是两个不同的函数,因此如果想要共享变量就需要通过IAsyncResult接口来访问容器中的值,这样显然增加了我们的工作量。
* 第二种写法更为优雅,这似乎是C#语言中某种高级语法,具体叫什么我忘了,反正在Linq中经常看到这种写法的影子。


综合以上两个观点,博主还是建议大家使用第二种写法,博主打算有空的话将之前写的程序再重新写一遍,看看能不能找出代码中的问题。好了,今天的内容就是这样了,谢谢大家,希望大家喜欢!


查看评论

C# Scoket异步通讯实现(发送数据、接收数据)

using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Ne...
  • smartsmile2012
  • smartsmile2012
  • 2017-05-04 17:09:02
  • 3848

C#:简单的Socket异步通信功能(客户端)

上一篇(http://www.rexcao.net/archives/159)讲了服务端使用Socket发送消息的方法,这一篇来解决一下客户端如何接收服务端消息的问题。 目标 1、异步接收...
  • jsjpanxiaoyu
  • jsjpanxiaoyu
  • 2016-10-28 13:07:21
  • 2864

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

Socket 请参考此链接来获取对于Socket的认识:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.aspx ...
  • jsjpanxiaoyu
  • jsjpanxiaoyu
  • 2016-10-28 13:02:59
  • 745

c# socket 异步通信,包括服务器端和客户端

  • 2009年08月02日 09:07
  • 14KB
  • 下载

C#Socket 网络通信异步处理

C#Socket 网络通信异步处理 SocketAsyncEventArgs 异步套接字操作 1.服务端简单实现: Code: public partial class Form...
  • heyangyi_19940703
  • heyangyi_19940703
  • 2017-07-18 18:47:48
  • 655

C#TCP Socket网络编程(异步通信方式)

一、Socket编程 Socket即为套接字,它其实是一个句柄,存在于内存中的一个标识符,作为网络通信的一个符号。 Socket类位于System.Net.Sockets命名空间,封装了与套接字编...
  • kevin_IoT
  • kevin_IoT
  • 2017-02-08 12:34:42
  • 1269

unity csharp socket 异步通信 客户端

点击打开链接 点击打开链接 点击打开链接 点击打开链接 点击打开链接 点击打开链接http://www.cnblogs.com/solq/archive/2012/04/23/2467342.html...
  • fanglrui
  • fanglrui
  • 2015-10-09 17:40:38
  • 1353

c#异步Socket Tcp服务器实现

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

C#Socket同步异步通讯总结笔记

同步套接字通信Socket支持下的网上点对点的通信服务端实现监听连接,客户端实现发送连接请求,建立连接后进行发送和接收数据的功能服务器端建立一个socket,设置好本机的ip和监听的端口与socket...
  • kenkao
  • kenkao
  • 2010-03-25 17:28:00
  • 11600

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

异步编写Socket客户端
  • qq5558809xv
  • qq5558809xv
  • 2016-11-17 18:47:03
  • 1735
    个人资料
    持之以恒
    等级:
    访问量: 55万+
    积分: 6289
    排名: 4890
    最新评论