如何使用多个端口或其他方式连接到具有tcp客户端的调制解调器?
我有大约5000个调制解调器(瘦客户端),我想与他们沟通,我的方法之一是这样的:string GetModemData(modemID)
,现在我有一个开放的服务器端口监听调制解调器,我使用套接字编程发送数据到调制解调器(调用相关功能),但是当我想要在同一时间内向多个调制解调器发送数据并获得响应时,我不知道该怎么办?我可以发送数据到一个调制解调器并等待它的响应,然后发送另一个数据到其他调制解调器(顺序),但问题是客户端应该等待很长时间才能得到答案(可能是某些不同的客户端想从调制解调器获取某些信息所以他们都会等待Q或类似的东西),我认为解决这个问题的一种方法是使用多个端口,并监听每个调制解调器到相关的端口,但它占用太多的端口,也可能是内存使用量超出我的可用内存空间,所以可能会发生一些丢失(这是真的吗?)。该怎么办?我会考虑Parallelism,但我认为它不相关,我应该等待一个端口,因为我不知道应该将当前接收的数据传递给哪个客户端。我正在使用asp.net。如何使用多个端口或其他方式连接到具有tcp客户端的调制解调器?
目前我在做这样的:
private void StartListener()
{
ModemTcpListener = new TcpListener(ModemPort);
//ClientTcpListener = new TcpListener(ClientPort);
ModemTcpListener.Start();
ModemTcpListener.BeginAcceptTcpClient(new AsyncCallback(DoAcceptModemCallback), ModemTcpListener);
}
,作为回报,
private void DoReadModemCallback(IAsyncResult ar)
{
try
{
bool bRet = ar.AsyncWaitHandle.WaitOne(420000);
Modem modem = ar.AsyncState as Modem;
if (!bRet || modem == null)
{
return;
}
}
catch{}
// now send data to which client?????? if i'm going to use async????
}
和:
private void DoAcceptModemCallback(IAsyncResult ar)
{
try
{
ModemTcpListener.BeginAcceptTcpClient(new AsyncCallback(DoAcceptModemCallback), ModemTcpListener);
TcpClient tcpClient = ModemTcpListener.EndAcceptTcpClient(ar);
Modem modem= new Modem(tcpClient, "");
tcpClient.GetStream().BeginRead(modem.Buffer, 0, tcpClient.ReceiveBufferSize, new AsyncCallback(DoReadModemCallback), modem);
ModemTcpListener.BeginAcceptTcpClient(new AsyncCallback(DoAcceptModemCallback), ModemTcpListener);
Log.Write("a Modem connect ...");
}
catch (Exception ex)
{
}
}
这里有一个例子跟踪所有的客户端。为了可读性,我压缩了它。你应该真的把它分成多个类。
我使用池(我刚刚创建并提交)和SimpleServer。这两个类都是我目前正在构建的库的一部分(但远没有完成)。
不要害怕打开5000个套接字,当您使用异步操作时,它们不会消耗太多资源。
public class SuperServer
{
private List<ClientContext> _clients = new List<ClientContext>();
private SimpleServer _server;
private Pool<byte[]> _bufferPool;
public SuperServer()
{
// Create a buffer pool to be able to reuse buffers
// since your clients will most likely connect and disconnect
// often.
//
// The pool takes a anonymous function which should return a new buffer.
_bufferPool = new Pool<byte[]>(() => new byte[65535]);
}
public void Start(IPEndPoint listenAddress)
{
_server = new SimpleServer(listenAddress, OnAcceptedSocket);
// Allow five connections to be queued (to be accepted)
_server.Start(5);
}
// you should handle exceptions for the BeginSend
// and remove the client accordingly.
public void SendToAll(byte[] info)
{
lock (_clients)
{
foreach (var client in _clients)
client.Socket.BeginSend(info, 0, info.Length, SocketFlags.None, null, null);
}
}
// Server have accepted a new client.
private void OnAcceptedSocket(Socket socket)
{
var context = new ClientContext();
context.Inbuffer = _bufferPool.Dequeue();
context.Socket = socket;
lock (_clients)
_clients.Add(context);
// this method will eat very few resources and
// there should be no problem having 5000 waiting sockets.
context.Socket.BeginReceive(context.Inbuffer, 0, context.Inbuffer.Length, SocketFlags.None, OnRead,
context);
}
//Woho! You have received data from one of the clients.
private void OnRead(IAsyncResult ar)
{
var context = (ClientContext) ar.AsyncState;
try
{
var bytesRead = context.Socket.EndReceive(ar);
if (bytesRead == 0)
{
HandleClientDisconnection(context);
return;
}
// process context.Inbuffer here.
}
catch (Exception err)
{
//log exception here.
HandleClientDisconnection(context);
return;
}
// use a new try/catch to make sure that we start
// read again event if processing of last bytes failed.
try
{
context.Socket.BeginReceive(context.Inbuffer, 0, context.Inbuffer.Length, SocketFlags.None, OnRead,
context);
}
catch (Exception err)
{
//log exception here.
HandleClientDisconnection(context);
}
}
// A client have disconnected.
private void HandleClientDisconnection(ClientContext context)
{
_bufferPool.Enqueue(context.Inbuffer);
try
{
context.Socket.Close();
lock (_clients)
_clients.Remove(context);
}
catch(Exception err)
{
//log exception
}
}
// One of your modems
// add your own state info.
private class ClientContext
{
public byte[] Inbuffer;
public Socket Socket;
}
}
使用的类:
谢谢,我会看到他们,现在我要睡觉了:D – 2010-10-27 19:49:19
您需要使用异步TCP/IP的方法。本文将介绍如何:
http://www.codeproject.com/KB/IP/asyncsockets.aspx
的关键部分是BeginReceive()和相关的回调函数。还有更多的问题,请给这个答案留下评论;)最好的运气!
此外,我建议你保持一个开放的连接数组,例如Socket [] = new Socket [5000];如果使用异步调用端口,则使用和内存不应该成为问题,因为处理将仅在打开的连接上发生,开始接收以及接收数据时(函数回调)。 – vdoogs 2010-10-27 18:18:22
该文章包含一些可能导致应用程序崩溃或意外行为的缺陷。它可以在一个或两个连接的套接字上正常工作。不要像在文章中那样混合使用线程和异步方法。并且从不检查一个事件为null,然后调用它,事件可能已被清除。不要用空的catch块来吃异常。 – jgauffin 2010-10-27 18:32:44
@jgauffin,我同意你的看法,但是vdoogs打开太多的socket并不能解决我的问题,我应该听哪个调制解调器在哪个socket?可能是我不能仔细说出我的问题,请看我对A_Nablsi的评论。 – 2010-10-27 18:37:28
只要客户端建立到服务器的连接,就需要多线程,为它启动一个新线程并启动通信发送/接收。
这里有一些文章解释在C#中的多线程, c-sharpcorner codeproject
而这里的多线程样本服务器应用程序, http://www.dotnetspider.com/resources/2829-A-multi-readed-server-C-which-finds-prime-num.aspx
想想这种情况:你有5个不同的客户端,他们想获取5个不同的瘦客户端数据,如果他们在单个端口上收听,我怎么能找到巫婆客户端接收到的巫婆数据以通过它?如果我连接到客户端与TCP IP或像这样我可以保存他们的IP地址(MAC或...)并发回数据给他们,但我使用asp.net只是一些函数调用,我不知道发送收到的数据给客户端。因为我不是主人,IIS将会这样做。 – 2010-10-27 18:25:25
我不会为每个客户创建一个新线程,这是一个非常低效的方式。改用异步IO(BeginRead/EndRead等)。 – jgauffin 2010-10-27 18:27:57
请问我需要更多解释我无法想象你如何保持与客户端在服务器上的连接,并且我不确定当你想获取他们的数据时,是否建立了从服务器到客户端的连接。当我想象客户端建立与服务器的连接时,您的应用程序必须保持对客户端套接字对象的引用,通过这种方式,您可以与所有客户端保持通信,或者通过多线程来保持其套接字对象的引用。 – 2010-10-27 18:43:55
你怎么在DoAcceptModemCallback吗? – 2010-10-27 18:51:08
现在你应该做的是保持列表中的调制解调器对象的引用,但你仍然有识别调制解调器的问题,调制解调器应用程序是你的,我的意思是你写了那个应用程序?如果你这么做,那么你应该让调制解调器在连接到服务器时向你发送一个标识。 – 2010-10-27 19:11:58
@A_Nablsi,Modem是我的班级,我可以跟踪他们,但在客户端我有一个问题(不是瘦客户端,调制解调器是瘦客户端)我找到了一个解决方案,但它的复杂,因为我会做太多的解析算法,我想找一个简单的方法,现在我要去睡觉了:D – 2010-10-27 19:53:39