.NET Socket开发(1) 之同步Socket实现

.NET Socket开发之同步Socket实现两例
今天,我们来讲一下在.NET 网络应用程序开发中同步Socket的应用,很多人认为在网络应用的服务端Socket不应该使用同步Socket。是的,在大多数情况下是这样的,但是也有一些场景下我们使用同步Socket可能会得到更的结果。如在下面的两种场景下我们便可以考虑使用同步的Socket。
一、客户端数量比较少:
数量比较少是指会同时连接到服务器的客户端数量一般在50人以下。这种情况下我们可以考虑使用同步Socket+Thread来实现我们的服务端。这样会让我们编写逻辑更清晰的代码而性能不会下降太多。
二、客户端数量较多但都是短连接:
短连接是指客户端的连接在处理完一次收发之后就产即断开的场景,比如说HTTP协议就是一种短连接。HTTP在客户端发出请求时建立一个Socket连接,并通过Socket发出一个URL请求,服务端在处理完这个请求并回发相应的页面后便会断开这个连接。那么在这种场景下我们也可以使用同步Socket来实现我们的需求。


那么应该如果实现我上面提到的两种需求呢。对于这两种需求,我将采用不同的方案来实现它们。
首先我们来看看第一种需求,这里我采用Socket+Thread来实现,基本的流程如下:
首先创建一个Socket,并且给它绑定一个EndPoint后开始监听。接下来我们创建一个线程,在这个线程中我们用一个无限循环来接收来自客户端的连接请求。在接收到一个请求后,为这个客户端创建一个新的线程,并且在这个线程中也使用一个无限循环接收来自这个客户端的数据。下面让我们来看看代码:

 

ExpandedBlockStart.gif 代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;
using  System.Net;
using  System.Net.Sockets;
using  System.Threading;

namespace  SocketServer
{
    
///   <summary>
    
///  Socket 同步通讯 Socket+Thread
    
///   </summary>
     public   class  SocketA
    {
        Socket server;
        
public  SocketA()
        {
            
// 创建一个Socket用来侦听客户端的连接
            server  =   new  Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            server.Bind(
new  IPEndPoint(IPAddress.Any, 9999 ));
            server.Listen(
100 );
            Console.WriteLine(
" 服务器启动...... " );

            
// 然后创建一个线程来处理客户端的连接请求
            Thread th  =   new  Thread( new  ThreadStart(WriteConnction));
            th.Start();
            Console.ReadLine();
        }

        
public   void  WriteConnction()
        {
            Thread.CurrentThread.IsBackground 
=   true ;
            
while ( true )
            {
                Socket s 
=  server.Accept();
                IPEndPoint ippoint 
= (IPEndPoint)s.RemoteEndPoint;
                Console.WriteLine(
" 收到连接,来自: "   +  ippoint.Address.ToString());
                
// 然后创建一个线程来接受信息
                Thread th  =   new  Thread( new  ParameterizedThreadStart(WriteMsg));
                th.Start(s);
            }
        }

        
public   void  WriteMsg( object  obj)
        {
            Thread.CurrentThread.IsBackground 
=   true ;
            
if (obj  != null )
            {
                Socket socket 
=  (Socket)obj;
                
byte [] byt = new   byte [ 1024 ];
                
while ( true )
                {
                    
int  getlength  =  socket.Receive(byt);
                    
if (getlength > 0 )
                    {
                        IPEndPoint ippoint 
=  (IPEndPoint)socket.RemoteEndPoint;
                        
string  address = ippoint.Address.ToString();
                        
string  msg  =  System.Text.Encoding.UTF8.GetString(byt,  0 , getlength);
                        Console.WriteLine(
" 收到来自 "   +  address + " 的消息: " + msg);

                        socket.Send(byt, getlength, SocketFlags.None);
                    }
                }
            }                  
        }

    }
}


 

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

 

ExpandedBlockStart.gif 代码
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;
using  System.Net;
using  System.Net.Sockets;
using  System.Threading;

namespace  SocketServer
{
    
///   <summary>
    
///  Socket 同步通讯 Socket+Thread
    
///  客户端数量比较少 
    
///   </summary>
     public   class  SocketB
    {
        Socket server;
        
public  SocketB()
        {
            
// 创建一个Socket用来侦听客户端的连接
            server  =   new  Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            server.Bind(
new  IPEndPoint(IPAddress.Any,  8888 ));
            server.Listen(
100 );
            Console.WriteLine(
" 服务器启动...... " );

            
// 创建一个线程池
            Thread[] ths = new  Thread[ 30 ];
            
for  ( int  i  =   0 ; i  <  ths.Length;i ++  )
            {
                ths[i] 
=   new  Thread( new  ThreadStart(WaiteConnetion));
            }
            Console.ReadLine();
        }

        
public   void  WaiteConnetion()
        {
            
byte [] byt = new   byte [ 1024 ];
            Socket s 
=  server.Accept();
            IPEndPoint ipoint
= (IPEndPoint)s.RemoteEndPoint;
            
string  ip = ipoint.Address.ToString();
            Console.WriteLine(
" 收到连接,来自: "   +  ip);
            
int  getlength  =  s.Receive(byt);
            
if (getlength > 0 )
            {
                
string  msg  =  System.Text.Encoding.UTF8.GetString(byt);
                Console.WriteLine(
" 收到信息 " + ip + " 来自 " + msg);
                s.Send(byt,getlength,SocketFlags.None);
            }
            s.Shutdown(SocketShutdown.Both);
            s.Close();
        }

    }
}

为什么我们要这样做呢?
首先我们创建了一个Socket用于侦听客户端的连接请求,接下我们创建了一个拥有30个线程的线程池。并在每个线程中实现了Accept、Receive、Send和Close(),以完成连接、接收、发送、关闭的操作。
现在我们假设有一个客户连接到服务器了,这时会有一个线程Accept到这个请求,并开始接收客户端发送过来的数据,接收到数据之后处理完发送给客户端,然后关闭这个连接,再次进入等待连接状态。而其它29个线程由于没有Accept到这个请求,仍然处理等待接入状态。

 

转载于:https://www.cnblogs.com/bobofsj11/archive/2010/01/08/1642170.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值