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

标签: socket编程 异步 编程 socket
6339人阅读 评论(6) 收藏 举报
分类:

本文将在C#中Socket同步通信的基础上,分析和研究Socket异步编程的实现方法,目的是深入了解Socket编程的基本原理,增强对网络游戏开发相关内容的认识。

什么是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#版 Socket编程(最简单的Socket通信功能)

示例程序是同步套接字程序,功能很简单,只是客户端发给服务器一条信息,服务器向客户端返回一条信息;这里只是一个简单的示例,是一个最基本的socket编程流程,在接下来的文章中,会依次记录套接字的同步和异...
  • e295166319
  • e295166319
  • 2016-10-13 16:43:22
  • 2379

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

本文通过分析和总结C#中Socket通信编程的关键技术,按照同步实现的方式实现了一个简单的Socket聊天程序,目的是通过这个程序来掌握Socket编程,为进一步开发Unity3D网络游戏打下一个...
  • mss359681091
  • mss359681091
  • 2016-06-30 15:44:32
  • 5775

c#Socket通信入门实例

在C#中使用socket通信,只要使用 visual studio中自带的 using System.Net和 using System.Net.Sockets;命名空间,这样就可以进行通信了。 ...
  • love_kevin
  • love_kevin
  • 2017-05-13 09:44:49
  • 2779

基于C# Winform的简易聊天程序[socket通信]

原理 启动服务端后,服务端通过持续监听客户端发来的请求,一旦监听到客户端传来的信息后,两端便可以互发信息了.服务端需要绑定一个IP,用于客户端在网络中寻找并建立连接.信息发送原理:将手动输入字符...
  • fsdad
  • fsdad
  • 2017-06-30 13:10:38
  • 1121

C# 服务端与客户端示例(Socket通信)

C# 服务端与客户端示例(Socket通信)
  • scimence
  • scimence
  • 2016-10-28 17:05:29
  • 10861

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

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

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

异步编写Socket客户端
  • qq5558809xv
  • qq5558809xv
  • 2016-11-17 18:47:03
  • 1735

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

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

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

异步编写Socket服务端
  • qq5558809xv
  • qq5558809xv
  • 2016-11-18 13:15:43
  • 968

C#Socket 网络通信异步处理

C#Socket 网络通信异步处理 SocketAsyncEventArgs 异步套接字操作 1.服务端简单实现: Code: public partial class Form...
  • heyangyi_19940703
  • heyangyi_19940703
  • 2017-07-18 18:47:48
  • 655
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 157万+
    积分: 1万+
    排名: 800
    公众号推广
    最新评论