关闭

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

标签: socket编程异步编程socket
5886人阅读 评论(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中经常看到这种写法的影子。

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

1
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

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

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

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

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

C# Socket编程 同步以及异步通信

套接字简介:套接字最早是Unix的,window是借鉴过来的。TCP/IP协议族提供三种套接字:流式、数据报式、原始套接字。其中原始套接字允许对底层协议直接访问,一般用于检验新协议或者新设备问题,很少...
  • luckypeng
  • luckypeng
  • 2014-05-13 14:40
  • 2302

c# Socket 异步客户端服务端

废话不多说  直接上代码 服务端: using System; using System.Collections.Generic; using System.ComponentMode...
  • everlasting51
  • everlasting51
  • 2014-02-20 18:55
  • 1106

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

原创性声明 本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处 本文介绍 在.Net中,Sy...
  • zhujunxxxxx
  • zhujunxxxxx
  • 2015-03-15 21:20
  • 7717

c#异步Socket Tcp服务器实现

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

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

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

Unity3d-c# Socket异步通讯与Unity组件数据更新的处理

首先基于C#的Socket的BeginReceive异步接收和BeginSend异步发送数据的底层的实现也是多线程处理,当然也可以自己用线程来实现;C#的异步Socket简单的例子和教程网上很多,在此...
  • a615538001
  • a615538001
  • 2016-10-24 21:28
  • 1421

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# Scoket异步通讯实现(发送数据、接收数据)

using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Ne...
  • smartsmile2012
  • smartsmile2012
  • 2017-05-04 17:09
  • 2351
    个人资料
    • 访问:1443672次
    • 积分:15501
    • 等级:
    • 排名:第829名
    • 原创:207篇
    • 转载:0篇
    • 译文:0篇
    • 评论:1394条
    公众号推广

     欢迎订阅公众号【5厘米的理想】
     一起:探讨技术心得,交流生活感悟
    关于作者
    Payne,一名文艺的程序员
    19岁以前写诗,19岁以后写代码
    欢迎大家同我:
    探讨技术心得,交流生活感悟
    -------------------------------------------
    个人博客:->点此访问
    知乎专栏:->点此访问
    -------------------------------------------
    微信:@PayneQin(请说明来意)
    微博:@飞鸿踏雪(请随意关注)
    知乎:@飞鸿踏雪(请随意关注)
    邮件:qinyuanpei@163.com(请说明来意)
    最新评论