.NET Socket开发之异步Socket

转载 2007年10月15日 15:24:00
在基于.NET的网络服务端的开发中,我们用到和听到的最多的恐怕就是异步Socket了。异步Socket的性能比同步高出很多,但是编写代码比较复杂。因此异步Socket也是网络上讨论比较多的话题。
今天,我们就来讨论一下如何用异步Socket开发网络应用。在此之前我们先讨论两个问题。
一、异步Socket是如何工作的:
那异步Socket是如何工作的呢?我以接收一条消息来说明这个问题。首先,程序向系统投递一个接收数据的请求,并为其指定一个数据缓冲区和回调函数,回调函数用来指示当数据到达后将如何处理,然后我们的程序继续执行下去,当有数据到达的时候,系统将数据读入缓冲区,并执行回调函数,处理这条消息。我们并不需要关心这条消息何时到达。
二、什么情况下我们用异步Socket:
有些人认为,异步Socket的性能比同步Socket的性能高很多,应该在各种环境下都用异步Socket,其实不然。在某些环境下面。异步反到比同步的性能低,那么在哪些情况下会这样呢?
1、客户端Socket。
2、服务端连接数比较少。
3、连接数很多,但都是短连接。
在这些环境下,我们用同步Socket不但可以简化代码,而且性能并不会比异步Socket低。但在服务端连接比较多而且是长连接的情况下,我们就要使用异步Socket。
现在我们来看看如何用异步Socket编程。
首先,我们要建立一个Socket用来监听:

            Socket _listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint localEP 
= new IPEndPoint(_address, _port);
            _listener.Bind(localEP);
            _listener.Listen(
100);
然后创建一个线程来处理客户端连接请求: 我们再来看看回调函数的定义:

        private void ReceiveCallBack(IAsyncResult ar)
        
{
            UserInfo info 
= (UserInfo)ar.AsyncState;
            Socket handler 
= info.socket;
            
int readCount = 0;
            
try
            
{
                readCount 
= handler.EndReceive(ar);//调用这个函数来结束本次接收并返回接收到的数据长度。
            }

            
catch (SocketException)//出现Socket异常就关闭连接
            {
                CloseSocket(info);
//这个函数用来关闭客户端连接
                return;
            }

            
catch
            
{
            }

            
if (readCount > 0)
            
{
                
byte[] buffer = new byte[readCount];
                Buffer.BlockCopy(info.Buffer, 
0, buffer, 0, readCount);
                Analyzer(info, buffer);
//这个函数用来处理接收到的信息。
                try
                
{
                    handler.BeginReceive(info.Buffer, 
0, info.Buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), info);//向系统投递下一个接收请求
                }

                
catch (SocketException) //出现Socket异常就关闭连接
                {
                    CloseSocket(info);
                }

                
catch
                
{
                }

            }

            
else //如果接收到0字节的数据说明客户端关闭了Socket,那我们也要关闭Socket
            {
                CloseSocket(info);
            }

        }
接下来我们看看如何发送数据给客户端:

        public void Send(Socket socket, byte message)
        
{
            
try
            
{
                info.socket.BeginSend(message, 
0, _byte.Length, SocketFlags.None, new AsyncCallback(SendCallBack), info);//这里向系统投递一个发送数据的请求,并指定一个回调函数。
            }

            
catch (SocketException ex)
            
{
                CloseSocket(info);
            }

            
catch
            
{
            }

        }
定义发送回调函数:

        private void SendCallBack(IAsyncResult ar)
        
{
            UserInfo info 
= (UserInfo)ar.AsyncState;
            
try
            
{
                info.socket.EndSend(ar);
//调用这个函数来结束本次发送。
            }

            
catch
            
{
            }

        }

 
好了,整个监听、接收、发送的过程就完成了,很简单吧。现在需要说明的是,我在这里接收客户端连接的Accept是用的同步的,我个人认为在这里用同步的会比用异步好一些。因为这样代码简单而且没有性能上的损失。
今天我就写到这里了!下次我们再继续。
posted on 2007-06-13 23:59 牧 野 阅读(2865) 评论(32)  编辑  收藏 所属分类: C#Socket
楼主对异步的认识大错特错
所谓的SOCKET采用异步会取得高效的性能说的就是Accept。我们应该用BeginAccept,因为如果用Accept的话,同时连接数量多的情况下就不能及时回应,而用BeginAccept就会很好的避免这个问题,所谓的SOCKET应该采用异步来提高性能,其实说的就是我们应该用BeginAccept。对于SEND和RECEIVE,你只要开一个线程在处理一个连接其实就相当于是BEGINSEND和BEGINRECEIVE,就是在异步处理了。有人说一个新连接开一个线程不好,如果有1000连接就要开1000个线程,所以应该采用异步,这简直就是天大的笑话,这些笨蛋们远不知道BEGINSEND等方法就是在线程池开的线程来处理。
BEGINSEND和BEGINRECEIVE在。NET1.1里根本就没有这两个方法,难道。NET1.1的SOCKET就不能异步了????????看了楼主的文章,其实很多东西楼主大大的理解错了。
@biaobiao
那你有没有查看过.NET的类库呢??
呵呵…………
BeginSned和BeginReceive可不是简单的丢在线程池里,他是投递到系统内核里去了。由系统内核来调度发送和接收的操作。
还要告诉你一点,在Socket编程中,线程不是越多越好,你知道性能最高的IOCP模式有多少个线程吗?CPU数量×2+2,就这么多。当一个程序的线程达到50个以上时,如果再增加线程,系统的性能会下降很多!看来你还要多学学!
你使用BeginAccept来接收Socket,而用Receive和Send来收发数据,这才是大错特错。回家好好看完书再来讨论。
还有,不要在我这里骂人,不然我会删除你的回复。那些被你骂成笨蛋的恰恰是比你更了解Windows开发的人。
牧野 的这篇文章没啥错的,我赞同他的观点,尤其是关于异步的好处,它绝非简单的把Socket操作抛到线程池里(我在刚开始用.NET 1.0的时候也有过这种想法),而是传给里系统内核,然后系统内核会把它最终传到硬件层,这时候用到的线程甚至根本不是CPU上的,而是通讯硬件中的,这种手法可以大量节约CPU资源.

还有就是关于线程的使用,应该尽量节约,尤其是在做有大量客户连接的服务器时,最好是一两个线程负责所有的客户请求. 我自己用的方法是把所有客户请求抛到一个队列里,有一个线程负责把请求从队列里取出来处理. 它好处有两个:

1. 节省并发线程
2. 是避免了多线程并发处理请求时的线程同步.

如果对异步Socket有疑惑,可以读下大师Jeffrey Richter的<<CLR via C#, Second Edition>>, 其中有一章讲.NET线程和异步操作,比MSDN讲的透彻.

最后说一下,我做开发的年头和数量不在作者之下,以上所说主要来自具体编程的实践体会.
再问一下..Socket断线后 是否可以自动重连

下面是连接程序
我想在网络断开的时候重新连,怎么改,谢谢
加注释的话异常是在已连接的socket申请连接
public void Connect2Server()
{
IPAddress ipAddress = IPAddress.Parse(szSvrIPAddr);
EndPoint remoteEP = new IPEndPoint(ipAddress, SvrPort);
/*
Socket SocketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

if (SocketClient.Connected)
{
SocketClient.Shutdown(SocketShutdown.Both);
SocketClient.Close();
Thread.Sleep(100);
}
*/

while(!SocketClient.Connected)
{
try
{
SocketClient.Connect(remoteEP);
}
catch(Exception exc)
{
Log.WriteEntry("Connect to Server Error:" + exc.Message, EventLogEntryType.Error, 2);
}
Thread.Sleep(30 * 1000); //30s
}
}
#1楼    回复  引用  查看    
 

            Thread _acceptWorkThread = new Thread(AcceptWorkThread);
            _acceptWorkThread.Start();

        
private void AcceptWorkThread()
        
{
            
while (_isListener)
            
{
                UserInfo info 
= new UserInfo();//这个UserInfo是用来保存客户信息的。
                info.socket = socket;
                Socket socket 
= _listener.Accept();
                
//这里进行其它处理。
                socket.BeginReceive(info.Buffer, 0, info.Buffer.Length, SocketFlags.None, ReceiveCallBack, info);//这里向系统投递一个接收信息的请求,并为其指定ReceiveCallBack做为回调函数
            }

        }

.net 中socket的异步长连接实例

最近在熟悉socket通讯,写一个简单的聊天实例,希望对以后的初学者有帮助..... 服务器端的界面    public partial class ClientSeverForm : Fo...
  • evonne520
  • evonne520
  • 2011-08-11 12:49:30
  • 2052

System.Net.Socket 异步实现

TCPServer 1、使用的通讯通道:socket 2、用到的基本功能: Bind, Listen,BeginAccept,EndAccept,BeginReceive,EndReceive...
  • arhaiyun
  • arhaiyun
  • 2012-08-23 10:40:29
  • 1647

c# Socket 异步客户端服务端

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

.NET关于同步、异步及Socket

以SOCKET通信中的异步方法为例:public static ManualResetEvent ConnectDone = new ManualResetEvent(false);     publ...
  • lanwilliam
  • lanwilliam
  • 2008-05-05 09:46:00
  • 606

Socket开发之异步Socket

  • 2009年03月11日 10:32
  • 26KB
  • 下载

VB.Net中Socket异步编程的实例

Imports System Imports System.Net Imports System.Net.Sockets Imports System.Text Imports System.Thre...
  • Seal203
  • Seal203
  • 2015-06-09 07:07:29
  • 3136

.net socket与完成端口、异步发送相关研究

原帖地址:http://www.cnsw.org/bbs/thread-68634-1-1.html 经过一番研究,终于可以确认,.net socket的beginSend和beginReceive用...
  • kenkao
  • kenkao
  • 2011-03-10 10:00:00
  • 5146

.net C# 异步Socket 发送类.

采用异步
  • daonidedie
  • daonidedie
  • 2014-11-21 10:57:45
  • 1125

TCP异步Socket经典例子C# .Net

  • 2010年05月15日 10:40
  • 112KB
  • 下载

c# socket 客户端异步实现

简易封装:using System; using System.Collections.Generic; using System.Linq; using System.Text; using Sys...
  • wyljz
  • wyljz
  • 2017-09-12 11:05:26
  • 319
收藏助手
不良信息举报
您举报文章:.NET Socket开发之异步Socket
举报原因:
原因补充:

(最多只允许输入30个字)