C# 允许数百个TCP客户端在一两秒内连接
因此,使用我的软件,我在网络上发送一个发现广播,接收该广播的每个“客户端”都将通过TCP连接到我。就我所拥有的而言,这似乎“还可以”,但我觉得必须有更好的方法。我看到的是,我的软件中的一些TCP连接被拒绝(我想),因为我目前正在接受另一个套接字。因此,在我目前的版本中,我可以接受80%左右的时间使用套接字。有时更多,但通常在80%左右。其余的都被我的软件拒绝了,我不知道为什么。对我来说这是不可接受的,但我很难提高这个数字 下面是一个类,我用来接受TCP客户端,并通知另一个类已连接的新套接字:C# 允许数百个TCP客户端在一两秒内连接,c#,sockets,tcp,C#,Sockets,Tcp,因此,使用我的软件,我在网络上发送一个发现广播,接收该广播的每个“客户端”都将通过TCP连接到我。就我所拥有的而言,这似乎“还可以”,但我觉得必须有更好的方法。我看到的是,我的软件中的一些TCP连接被拒绝(我想),因为我目前正在接受另一个套接字。因此,在我目前的版本中,我可以接受80%左右的时间使用套接字。有时更多,但通常在80%左右。其余的都被我的软件拒绝了,我不知道为什么。对我来说这是不可接受的,但我很难提高这个数字 下面是一个类,我用来接受TCP客户端,并通知另一个类已连接的新套接字: p
public class AsynchronousSocketListener
{
// Thread signal.
public ManualResetEvent allDone = new ManualResetEvent(false);
public event EventHandler<ErtdRawDataArgs> ClientConnected;
private string bindingIp;
public string AddressBind
{
get { return this.bindingIp; }
private set { this.bindingIp = value; }
}
private int port;
public int Port
{
get { return this.port; }
private set { this.port = value; }
}
private Socket listener;
public AsynchronousSocketListener(string bindingIp, int port)
{
this.bindingIp = bindingIp;
this.port = port;
}
protected void OnClientConnected(string data, IPEndPoint clientEP)
{
if (this.ClientConnected == null)
return;
Task.Factory.StartNew(() =>
{
//build args
ErtdRawDataArgs args = new ErtdRawDataArgs(Encoding.Default.GetBytes(data));
args.Source = string.Format("{0}:{1}", clientEP.Address.ToString(), clientEP.Port);
this.ClientConnected(this, args);
});
}
public void Close()
{
if (this.listener == null || !this.listener.Connected)
return;
this.listener.Shutdown(SocketShutdown.Both);
this.listener.Close();
}
public void StartListening()
{
Task.Factory.StartNew(() =>
{
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse(this.bindingIp), this.port);
// Create a TCP/IP socket.
listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
int maxConnections = (int)SocketOptionName.MaxConnections;
listener.Listen(maxConnections);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
});
}
public void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket) ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
public void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject) ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0) {
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(
state.buffer,0,bytesRead));
// Check for end-of-file tag. If it is not there, read
// more data.
content = state.sb.ToString();
OnClientConnected(content, handler.RemoteEndPoint as IPEndPoint);
//close socket
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
}
}
公共类异步SocketListener
{
//线程信号。
public ManualResetEvent allDone=新的ManualResetEvent(false);
公共事件事件处理程序ClientConnected;
私有字符串绑定IP;
公共字符串地址绑定
{
获取{返回this.bindingIp;}
私有集{this.bindingIp=value;}
}
专用int端口;
公共int端口
{
获取{返回this.port;}
私有集{this.port=value;}
}
专用套接字侦听器;
公共异步SocketListener(字符串绑定IP,int端口)
{
this.bindingIp=bindingIp;
this.port=端口;
}
客户端连接时受保护的void(字符串数据、IPEndPoint客户端)
{
if(this.ClientConnected==null)
返回;
Task.Factory.StartNew(()=>
{
//构建args
ErtdRawDataArgs args=新的ErtdRawDataArgs(Encoding.Default.GetBytes(data));
args.Source=string.Format(“{0}:{1}”,clientEP.Address.ToString(),clientEP.Port);
this.ClientConnected(this,args);
});
}
公众假期结束()
{
if(this.listener==null | |!this.listener.Connected)
返回;
this.listener.Shutdown(SocketShutdown.Both);
this.listener.Close();
}
公营机构
{
Task.Factory.StartNew(()=>
{
//输入数据的数据缓冲区。
字节[]字节=新字节[1024];
//为套接字建立本地端点。
IPEndPoint localEndPoint=新的IPEndPoint(IPAddress.Parse(this.bindingIp)、this.port);
//创建TCP/IP套接字。
侦听器=新套接字(AddressFamily.InterNetwork、SocketType.Stream、ProtocolType.Tcp);
//将套接字绑定到本地端点并侦听传入连接。
尝试
{
Bind(localEndPoint);
int maxConnections=(int)SocketOptionName.maxConnections;
listener.Listen(maxConnections);
while(true)
{
//将事件设置为非信号状态。
全部完成。重置();
//启动异步套接字以侦听连接。
listener.beginacept(
新建异步回调(AcceptCallback),
听众);
//等待连接完成后再继续。
全部完成。WaitOne();
}
}
捕获(例外e)
{
Console.WriteLine(如ToString());
}
});
}
公共无效接受回调(IAsyncResult ar)
{
//向主线程发出继续的信号。
allDone.Set();
//获取处理客户端请求的套接字。
套接字侦听器=(套接字)ar.AsyncState;
套接字处理程序=listener.EndAccept(ar);
//创建状态对象。
StateObject状态=新的StateObject();
state.workSocket=处理程序;
handler.BeginReceive(state.buffer,0,StateObject.BufferSize,0,
新的异步回调(ReadCallback),状态);
}
公共void ReadCallback(IAsyncResult ar)
{
String content=String.Empty;
//检索状态对象和处理程序套接字
//从异步状态对象。
StateObject状态=(StateObject)ar.AsyncState;
套接字处理程序=state.workSocket;
//从客户端套接字读取数据。
int bytesRead=handler.EndReceive(ar);
如果(字节读取>0){
//可能会有更多数据,因此请存储到目前为止收到的数据。
state.sb.Append(Encoding.ASCII.GetString(
state.buffer,0,bytesRead));
//检查文件结尾标记。如果不存在,请读取
//更多数据。
content=state.sb.ToString();
OnClient已连接(内容,handler.RemoteEndPoint作为IPEndPoint);
//闭合插座
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
}
}
是否有任何方法可以改进此代码,或者是否有完全不同的方法来改进我在几乎相同的时间接受TCP连接的结果?嗯,在接受连接和“建立”连接之间有一段时间,然后才能接受另一个连接。使用诸如等待句柄之类的东西可能相当慢
重新阅读代码后,从概念上讲,您可以接受另一个连接的时间点是调用EndAccept
。似乎是在调用EndAccept
之前设置了事件,这意味着可以在EndAccept
之前调用beginacept
,并且可以在调用上一个hadEndAccept
之前接受另一个连接。我不知道这是否是个问题——据我所知,这是合法的。但是,您可以简化代码以避免事件,并在当前accept期间简单地链接下一个BeginAccept,并确保EndAccept
listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(new IPEndPoint(IPAddress.Any, 62000));
listener.Listen(1000);
listener.BeginAccept(OnAccept, listener);
private void OnAccept(IAsyncResult ar)
{
Socket listener = (Socket)ar.AsyncState;
Socket socket = listener.EndAccept(ar);
listener.BeginAccept(OnAccept, listener);
socket.BeginReceive(new byte[10], 0, 10, 0, (arReceive) => socket.EndReceive(arReceive), null);
}