TCP服务器可以开始与客户端通信

时间:2014-07-07 16:30:41

标签: c# async-await tcpclient tcplistener

我有异步tcp服务器,可以同时接受多个客户端。客户端从服务器请求数据的方案很好。现在我正在尝试实现服务器必须找到特定客户端并向其发送一些数据的情况,即客户端已连接但未请求数据但服务器想要向其发送一些数据。如何找到服务器和客户端之间已经运行的线程并在其上放置数据?

这是服务器代码:

public async void RunServerAsync()
{
    tcpListener.Start();           

        while (true)
        {
            try
            { 
               var client = await tcpListener.AcceptTcpClientAsync();           
               Accept(client); 
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);                      
            }                  
         }                         
}

private async void Accept(TcpClient client)
{
   //get client information 
    String clientEndPoint = client.Client.RemoteEndPoint.ToString();            
    Console.WriteLine("Client connected at " + clientEndPoint );

    await Task.Yield ();

    try 
    {              
        using (client)
        using (NetworkStream stream = client.GetStream()) 
        {
            byte[] dataReceived = new byte[100];                  
            while (true) //read input stream                    
            {                    
                  try
                 {
                     int x = await stream.ReadAsync(dataReceived, 0, dataReceived.Length);

                     if (x != 0)
                     {                              
                         //pass on data for processing    

                         byte[] dataToSend = await ProcessData(dataReceived);

                         //send response,if any, to the client 
                         if (dataToSend != null)
                         {
                             await stream.WriteAsync(dataToSend, 0, dataToSend.Length);
                             ConsoleMessages.DisplayDataSent(dataReceived, dataToSend);
                         }
                     }
                 }
                 catch (ObjectDisposedException)
                 {
                     stream.Close();
                 }
            }                   
        }
    } //end try           
    catch (Exception ex) 
    {
        Console.WriteLine(ex.Message);

    }
}//end Accept(TcpClient client)

2 个答案:

答案 0 :(得分:2)

您需要跟踪您的客户。例如:

ConcurrentDictionary<Guid, TcpClient> _clients = new ConcurrentDictionary<Guid, TcpClient>();

public async void RunServerAsync()
{
    tcpListener.Start();

    while (true)
    {
        try
        {
            var client = await tcpListener.AcceptTcpClientAsync();
            var clientId = Guid.NewGuid();
            Accept(clientId, client);
            _clients.TryAdd(clientId, client);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}

public Task SendAsync(Guid clientId, Byte[] buffer, Int32 offset, Int32 count)
{
    TcpClient client;
    if (_clients.TryGetValue(clientId, out client))
        return client.GetStream().WriteAsync(buffer, offset, count);

    // client disconnected, throw exception or just ignore
    return Task.FromResult<Object>(null);
}

public Boolean TryGetClient(Guid clientId, out TcpClient client)
{
    return _clients.TryGetValue(clientId, out client);
}

private async void Accept(Guid clientId, TcpClient client)
{
    //get client information 
    String clientEndPoint = client.Client.RemoteEndPoint.ToString();
    Console.WriteLine("Client connected at " + clientEndPoint);

    await Task.Yield();

    try
    {
        using (client)
        using (NetworkStream stream = client.GetStream())
        {
            byte[] dataReceived = new byte[100];
            while (true) //read input stream                    
            {
                try
                {
                    int x = await stream.ReadAsync(dataReceived, 0, dataReceived.Length);

                    if (x != 0)
                    {
                        //pass on data for processing    

                        byte[] dataToSend = await ProcessData(dataReceived);

                        //send response,if any, to the client 
                        if (dataToSend != null)
                        {
                            await stream.WriteAsync(dataToSend, 0, dataToSend.Length);
                            ConsoleMessages.DisplayDataSent(dataReceived, dataToSend);
                        }
                    }
                }
                catch (ObjectDisposedException)
                {
                    stream.Close();
                }
            }
        }
    } //end try           
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);

    }
    finally
    {
        // deregister client
        _clients.TryRemove(clientId, out client);
    }
}//end Accept(TcpClient client)

答案 1 :(得分:1)

TCP是双向的,因此任何一方都可以随时发送数据。

您需要做的是在Accept上存储对TcpClient的引用,例如:

//Class Level
List<TcpClient> connectedClients = List<TcpClient>();

private async void Accept(TcpClient client)
{
    connectedClients.Add(client);
    ...
}

public SendMessage(int index, String message)
{
   //pseudo-code
   connectedClients[index].Send(message);
}

通常我会在连接上引发一个事件,所以无论谁使用该类都可以获得新客户端的索引。发送消息代码是伪代码,在MSDN上有很好的例子说明如何实际执行发送。