• <转载>.NET Socket开发之同步Socket实现两例


    今天,我们来讲一下在.NET 网络应用程序开发中同步Socket的应用,很多人认为在网络应用的服务端Socket不应该使用同步Socket。是的,在大多数情况下是这样的,但是也有一些场景下我们使用同步Socket可能会得到更的结果。如在下面的两种场景下我们便可以考虑使用同步的Socket。
     
    一、客户端数量比较少:
     
    数量比较少是指会同时连接到服务器的客户端数量一般在50人以下。这种情况下我们可以考虑使用同步Socket+Thread来实现我们的服务端。这样会让我们编写逻辑更清晰的代码而性能不会下降太多。
     
    二、客户端数量较多但都是短连接:
     
    短连接是指客户端的连接在处理完一次收发之后就产即断开的场景,比如说HTTP协议就是一种短连接。HTTP在客户端发出请求时建立一个Socket连接,并通过Socket发出一个URL请求,服务端在处理完这个请求并回发相应的页面后便会断开这个连接。那么在这种场景下我们也可以使用同步Socket来实现我们的需求。
     
    那么应该如果实现我上面提到的两种需求呢。对于这两种需求,我将采用不同的方案来实现它们。
     
    首先我们来看看第一种需求,这里我采用Socket+Thread来实现,基本的流程如下:
     
    首先创建一个Socket,并且给它绑定一个EndPoint后开始监听。接下来我们创建一个线程,在这个线程中我们用一个无限循环来接收来自客户端的连接请求。在接收到一个请求后,为这个客户端创建一个新的线程,并且在这个线程中也使用一个无限循环接收来自这个客户端的数据。下面让我们来看看代码:
     
     
     
    首先我们创建一个Socket用来侦听客户端的连接
    Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    IPEndPoint locEP
    = new IPEndPoint(IPAddress.Any, 2000);
    listener.Bind(locEP);
    listener.Listen(
    100);
     
    然后创建一个线程来处理客户端的连接请求:
    Thread acceptThread = new Thread(new ThreadStart(AcceptWorkThread));
    acceptThread.Start();

    private void AcceptWorkThread()
    {
    Thread.CurrentThread.IsBackground
    = true;
    while (true)
    {
    Socket accept
    = listener.Accept();
    IPEndPoint remoEP
    = (IPEndPoint)accept.RemoteEndPoint;
    string recString = "接收到来自" + remoEP.Address.ToString() + "的连接。";
    this.Invoke(new AddListItemHandler(this.AddListItem), new string[] { recString });
    Thread receiveThread
    = new Thread(new ParameterizedThreadStart(ReceiveWorkThread));
    receiveThread.Start(accept);
    }
    }
     
     最后我们来看看如何接收数据:
     
    private void ReceiveWorkThread(object obj)
    {
    Thread.CurrentThread.IsBackground
    = true;
    Socket socket
    = (Socket)obj;
    byte[] buffer = new byte[1024];
    while (true)
    {
    int receiveCount = socket.Receive(buffer);
    if (receiveCount > 0)
    {
    IPEndPoint remoEP
    = (IPEndPoint)socket.RemoteEndPoint;
    string recString = "来自客户端" + remoEP.Address.ToString() + "的消息:" + Encoding.Default.GetString(buffer, 0, receiveCount);
    this.Invoke(new AddListItemHandler(this.AddListItem), new string[] { recString });
    socket.Send(buffer, receiveCount, SocketFlags.None);
    }
    else
    {
    socket.Close();
    break;
    }
    }
    }

    好了,整个实现就完成了。
     
    现在让我们来看看第二个需求:
     
    这个方案我们将采用另外一个方法来实现,为什么不采用上一个方法来实现呢?让我们来分析一下。我们知道,在上一个实现中,每接入一个客户端就要创建一个线程,如果有大量的客户端接入的话,就会创建过多的线程。但是如果线程过多的话,Windows就需要更多的CPU时间来切换线程的上下文(这也是上一个实现不能接入很多客户端的原因)。
     
    我们知道,在这个方案中每一个连接都是短连接。而且顺序都是固定的。都是:接入->接收->发送这样的顺序,那么我们就可以在一个方法中完成整个处理。这样,我们就可以利用线程池来实现我们所需要的。好了,让我们用代码来说话吧:
     
     
     
    首先我们创建一个Socket用来侦听客户端的连接:

    Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    IPEndPoint locEP
    = new IPEndPoint(IPAddress.Any, 2000);
    listener.Bind(locEP);
    listener.Listen(
    100);

     
    接下来我们要创建一个线程池:
    Thread[] ClientThreadList = new Thread[30];
    foreach (Thread th in ClientThreadList)
    {
    th
    = new Thread(new ThreadStart(ClientWorkThread));
    th.Start();
    }
    最后让我们看看线程都要做些什么:
    private void ClientWorkThread()
    {
    byte[] buffer = new byte[1024];
    while (true)
    {
    Socket socket
    = listener.Accept();
    string recString = "接收到来自" + remoEP.Address.ToString() + "的连接。";
    this.Invoke(new AddListItemHandler(this.AddListItem), new string[] { recString });
    int receCount = socket.Receive(buffer);
    if (receCount>0)
    {
    string recString = "来自客户端" + remoEP.Address.ToString() + "的消息:" + Encoding.Default.GetString(buffer, 0, receiveCount);
    this.Invoke(new AddListItemHandler(this.AddListItem), new string[] { recString });
    socket.Send(buffer, receCount, SocketFlags.None);
    }
    socket.Shutdown(SocketShutdown.Both);
    socket.Close();
    }
    }
    为什么我们要这样做呢?
    首先我们创建了一个Socket用于侦听客户端的连接请求,接下我们创建了一个拥有30个线程的线程池。并在每个线程中实现了Accept、Receive、Send和Close(),以完成连接、接收、发送、关闭的操作。
    现在我们假设有一个客户连接到服务器了,这时会有一个线程Accept到这个请求,并开始接收客户端发送过来的数据,接收到数据之后处理完发送给客户端,然后关闭这个连接,再次进入等待连接状态。而其它29个线程由于没有Accept到这个请求,仍然处理等待接入状态。

    本文出处:http://blog.csdn.net/wzd24/archive/2007/10/12/1821386.aspx
  • 相关阅读:
    二分查找 java代码
    Failed at the bitcore-node@3.1.3 preinstall script './scripts/download' 设置linux proxy (代理)的方式
    github命令行实用操作
    H5无障碍旁白模式使用网页支持
    Vue框架搭建入门到熟悉
    解决IOS下返回不刷新的问题
    小程序—跳转 数据传递
    微信小程序——地图
    常用的正则判断
    JS 控制输入框输入表情emoji 显示在页面上
  • 原文地址:https://www.cnblogs.com/ChangTan/p/2050463.html
Copyright © 2020-2023  润新知