c#

位置:IT落伍者 >> c# >> 浏览文章

.NET Socket开发之同步Socket实现两例


发布日期:2019年08月01日
 
.NET Socket开发之同步Socket实现两例

今天我们来讲一下在NET 网络应用程序开发中同步Socket的应用很多人认为在网络应用的服务端Socket不应该使用同步Socket是的在大多数情况下是这样的但是也有一些场景下我们使用同步Socket可能会得到更的结果如在下面的两种场景下我们便可以考虑使用同步的Socket

客户端数量比较少

数量比较少是指会同时连接到服务器的客户端数量一般在人以下这种情况下我们可以考虑使用同步Socket+Thread来实现我们的服务端这样会让我们编写逻辑更清晰的代码而性能不会下降太多

客户端数量较多但都是短连接

短连接是指客户端的连接在处理完一次收发之后就产即断开的场景比如说HTTP协议就是一种短连接HTTP在客户端发出请求时建立一个Socket连接并通过Socket发出一个URL请求服务端在处理完这个请求并回发相应的页面后便会断开这个连接那么在这种场景下我们也可以使用同步Socket来实现我们的需求

那么应该如果实现我上面提到的两种需求呢对于这两种需求我将采用不同的方案来实现它们

首先我们来看看第一种需求这里我采用Socket+Thread来实现基本的流程如下

首先创建一个Socket并且给它绑定一个EndPoint后开始监听接下来我们创建一个线程在这个线程中我们用一个无限循环来接收来自客户端的连接请求在接收到一个请求后为这个客户端创建一个新的线程并且在这个线程中也使用一个无限循环接收来自这个客户端的数据下面让我们来看看代码

首先我们创建一个Socket用来侦听客户端的连接

Socket listener = new Socket(AddressFamilyInterNetwork

SocketTypeStream ProtocolTypeTcp);IPEndPoint locEP= new IPEndPoint(IPAddressAny );listenerBind(locEP);listenerListen();

然后创建一个线程来处理客户端的连接请求

Thread acceptThread = new Thread(new ThreadStart(AcceptWorkThread));acceptThreadStart(); private void AcceptWorkThread(){    ThreadCurrentThreadIsBackground = true;    while (true)    {        Socket accept = listenerAccept();        IPEndPoint remoEP = (IPEndPoint)acceptRemoteEndPoint;        string recString = 接收到来自 + remoEPAddressToString() + 的连接;        thisInvoke(new AddListItemHandler(thisAddListItem) new string[]

{ recString });        Thread receiveThread = new Thread(new ParameterizedThreadStart

(ReceiveWorkThread));        receiveThreadStart(accept);    }}

最后我们来看看如何接收数据

private void ReceiveWorkThread(object obj){    ThreadCurrentThreadIsBackground = true;    Socket socket = (Socket)obj;    byte[] buffer = new byte[];    while (true)    {        int receiveCount = socketReceive(buffer);        if (receiveCount > )        {            IPEndPoint remoEP = (IPEndPoint)socketRemoteEndPoint;            string recString = 来自客户端 + remoEPAddressToString() +

消息 + EncodingDefaultGetString(buffer receiveCount);            thisInvoke(new AddListItemHandler(thisAddListItem) new string[]

{ recString });            socketSend(buffer receiveCount SocketFlagsNone);        }        else        {            socketClose();            break;        }    }}

好了整个实现就完成了

现在让我们来看看第二个需求

这个方案我们将采用另外一个方法来实现为什么不采用上一个方法来实现呢?让我们来分析一下我们知道在上一个实现中每接入一个客户端就要创建一个线程如果有大量的客户端接入的话就会创建过多的线程但是如果线程过多的话Windows就需要更多的CPU时间来切换线程的上下文(这也是上一个实现不能接入很多客户端的原因)

我们知道在这个方案中每一个连接都是短连接而且顺序都是固定的都是接入>接收>发送这样的顺序那么我们就可以在一个方法中完成整个处理这样我们就可以利用线程池来实现我们所需要的好了让我们用代码来说话吧

首先我们创建一个Socket用来侦听客户端的连接

Socket listener = new Socket(AddressFamilyInterNetwork SocketTypeStream

ProtocolTypeTcp);IPEndPoint locEP= new IPEndPoint(IPAddressAny );listenerBind(locEP);listenerListen();

接下来我们要创建一个线程池

Thread[] ClientThreadList = new Thread[];foreach (Thread th in ClientThreadList){    th = new Thread(new ThreadStart(ClientWorkThread));    thStart();}

最后让我们看看线程都要做些什么

private void ClientWorkThread(){    byte[] buffer = new byte[];    while (true)    {        Socket socket = listenerAccept();        string recString = 接收到来自 + remoEPAddressToString() + 的连接

;        thisInvoke(new AddListItemHandler(thisAddListItem) new string[]

{ recString });        int receCount = socketReceive(buffer);        if (receCount>)        {            string recString = 来自客户端 + remoEPAddressToString() +

的消息 + EncodingDefaultGetString(buffer receiveCount);            thisInvoke(new AddListItemHandler(thisAddListItem) new string[]

{ recString });            socketSend(buffer receCount SocketFlagsNone);        }        socketShutdown(SocketShutdownBoth);        socketClose();    }}

为什么我们要这样做呢?

首先我们创建了一个Socket用于侦听客户端的连接请求接下我们创建了一个拥有个线程的线程池并在每个线程中实现了AcceptReceiveSend和Close()以完成连接接收发送关闭的操作

现在我们假设有一个客户连接到服务器了这时会有一个线程Accept到这个请求并开始接收客户端发送过来的数据接收到数据之后处理完发送给客户端然后关闭这个连接再次进入等待连接状态而其它个线程由于没有Accept到这个请求仍然处理等待接入状态

               

上一篇:12月编程语言排行榜:C#前途无亮

下一篇:ADO.NET操纵数据库