接受多个TCP客户机的最佳方法? [英] Best way to accept multiple tcp clients?

查看:161
本文介绍了接受多个TCP客户机的最佳方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个客户机/服务器基础设施。目前他们使用的TcpClient,并以的TcpListener所有客户端和服务器之间发送接收数据。当接收的数据(在它自己的线程)

I have a client/server infrastructure. At present they use a TcpClient and TcpListener to send a receive data between all the clients and server.

我目前做的是,它被放置在队列中,以便另一个线程以释放插座所以它来处理准备和开放接收新的数据。

What I currently do is when data is received (on it's own thread), it is put in a queue for another thread to process in order to free the socket so it is ready and open to receive new data.

                // Enter the listening loop.
                while (true)
                {
                    Debug.WriteLine("Waiting for a connection... ");

                    // Perform a blocking call to accept requests.
                    using (client = server.AcceptTcpClient())
                    {
                        data = new List<byte>();

                        // Get a stream object for reading and writing
                        using (NetworkStream stream = client.GetStream())
                        {
                            // Loop to receive all the data sent by the client.
                            int length;

                            while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
                            {
                                var copy = new byte[length];
                                Array.Copy(bytes, 0, copy, 0, length);
                                data.AddRange(copy);
                            }
                        }
                    }

                    receivedQueue.Add(data);
                }



不过,我想看看是否有更好的方式来做到这一点。例如,如果有10个客户,他们都希望将数据发送到在同一时间服务器,一会打通而如果一个客户有一个缓慢的连接和猪插座所有其他通信将停止所有的人将fail.Or 。

However I wanted to find out if there is a better way to do this. For example if there are 10 clients and they all want to send data to the server at the same time, one will get through while all the others will fail.Or if one client has a slow connection and hogs the socket all other communication will halt.

不是有一些方法能够在同一时间接收来自所有客户机的数据和在队列中进行处理时,它已经完成下载添加所接收到的数据?

Is there not some way to be able to receive data from all clients at the same time and add the received data in the queue for processing when it has finished downloading?

推荐答案

所以这里是一个答案,这将让你开始 - 这是比较初级的水平比我的博客文章

So here is an answer that will get you started - which is more beginner level than my blog post.

净有围绕一个开始*和*结束通话围绕异步模式。比如 - BeginReceive EndReceive 。他们几乎总是有其非异步对应物(在这种情况下,接收);并达到相同的目的。

.Net has an async pattern that revolves around a Begin* and End* call. For instance - BeginReceive and EndReceive. They nearly always have their non-async counterpart (in this case Receive); and achieve the exact same goal.

要记住的最重要的事情是在插槽的人做更多的不仅仅是拨打电话异步 - 他们揭露一些所谓的IOCP(IO完成港口的Linux /单声道有两个,但我忘了名字)在服务器上使用的是非常重要的;什么IOCP做的关键是,在等待数据的应用程序不占用一个线程。

The most important thing to remember is that the socket ones do more than just make the call async - they expose something called IOCP (IO Completion Ports, Linux/Mono has these two but I forget the name) which is extremely important to use on a server; the crux of what IOCP does is that your application doesn't consume a thread while it waits for data.

如何使用开始/结束模式

每一个开始*方法将在comparisson正好2个参数传递给它的非异步对口。第一个是一个AsyncCallback,第二个是一个对象。什么这两个意思是,在这里当您完成调用方法和这里是一些数据,我需要这个方法里面。这被称为永远的方法具有相同的签名,这个方法里面,你调用End *对口得到什么本来如果你已经同步完成它的结果。因此,例如:

Every Begin* method will have exactly 2 more arguments in comparisson to it's non-async counterpart. The first is an AsyncCallback, the second is an object. What these two mean is, "here is a method to call when you are done" and "here is some data I need inside that method." The method that gets called always has the same signature, inside this method you call the End* counterpart to get what would have been the result if you had done it synchronously. So for example:

private void BeginReceiveBuffer()
{
   _socket.BeginReceive(buffer, 0, buffer.Length, BufferEndReceive, buffer);
}

private void EndReceiveBuffer(IAsyncResult state)
{
   var buffer = (byte[])state.AsyncState; // This is the last parameter.
   var length = _socket.EndReceive(state); // This is the return value of the method call.
   DataReceived(buffer, 0, length); // Do something with the data.
}



这里发生的.NET是开始从插座中等待数据,一旦因为它得到的数据调用 EndReceiveBuffer ,并通过自定义数据通过传递(在这种情况下,缓存)将其 state.AsyncResult 。当你调用 EndReceive ,它会给你回所接收到的数据的长度(或抛出一个异常,如果事情失败)。

What happens here is .Net starts waiting for data from the socket, as soon as it gets data it calls EndReceiveBuffer and passes through the 'custom data' (in this case buffer) to it via state.AsyncResult. When you call EndReceive it will give you back the length of the data that was received (or throw an exception if something failed).

为套接字更好的模式

这形式会给你中央的错误处理 - 它可以在任何地方用在异步模式包装流般的东西(如TCP到达它发送的顺序,因此它可以被看作是一个对象)。

This form will give you central error handling - it can be used anywhere where the async pattern wraps a stream-like 'thing' (e.g. TCP arrives in the order it was sent, so it could be seen as a Stream object).

private Socket _socket;
private ArraySegment<byte> _buffer;
public void StartReceive()
{
    ReceiveAsyncLoop(null);
}

// Note that this method is not guaranteed (in fact
// unlikely) to remain on a single thread across
// async invocations.
private void ReceiveAsyncLoop(IAsyncResult result)
{
    try
    {
        // This only gets called once - via StartReceive()
        if (result != null)
        {
            int numberOfBytesRead = _socket.EndReceive(result);
            if(numberOfBytesRead == 0)
            {
                OnDisconnected(null); // 'null' being the exception. The client disconnected normally in this case.
                return;
            }

            var newSegment = new ArraySegment<byte>(_buffer.Array, _buffer.Offset, numberOfBytesRead);
            // This method needs its own error handling. Don't let it throw exceptions unless you
            // want to disconnect the client.
            OnDataReceived(newSegment);
        }

        // Because of this method call, it's as though we are creating a 'while' loop.
        // However this is called an async loop, but you can see it the same way.
        _socket.BeginReceive(_buffer.Array, _buffer.Offset, _buffer.Count, SocketFlags.None, ReceiveAsyncLoop, null);
    }
    catch (Exception ex)
    {
        // Socket error handling here.
    }
}



接受多个连接

在一般做的是什么编写包含您的插座等(以及你的异步循环)一类,并创建一个为每个客户端。因此,例如:

What you generally do is write a class that contains your socket etc. (as well as your async loop) and create one for each client. So for instance:

public class InboundConnection
{
    private Socket _socket;
    private ArraySegment<byte> _buffer;

    public InboundConnection(Socket clientSocket)
    {
        _socket = clientSocket;
        _buffer = new ArraySegment<byte>(new byte[4096], 0, 4096);
        StartReceive(); // Start the read async loop.
    }

    private void StartReceive() ...
    private void ReceiveAsyncLoop() ...
    private void OnDataReceived() ...
}

每个客户端连接应该由你的服务器类进行跟踪(这样就可以干净地断开它们在服务器关机,以及搜索/查找它们)。

Each client connection should be tracked by your server class (so that you can disconnect them cleanly when the server shuts down, as well as search/look them up).

这篇关于接受多个TCP客户机的最佳方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆