多线程TCP服务器回显到所有客户端

本文关键字:客户端 TCP 服务器 多线程 | 更新日期: 2023-09-27 17:49:26

我一直在TCP NAT穿孔服务器/客户端聊天室设置。我已经成功地在UDP中设置了它,现在我想为TCP做同样的事情,因为我对我的套接字atm有点粗糙。

客户端可以正常连接并聊天并接收回显,但根据连接的数量,它将根据连接的数量回显给发送消息的同一客户端。例如,3个客户端连接到client2发送一个ping,它返回给客户2 3次。它应该通过一个包含所有连接用户的IPEndPoint List的循环,并执行一个sock.SendTo(data,data. length,clients[i]);

,但它回显到发送消息的客户端。不知道我做错了什么,但我认为我做得很好。但这让我很困扰。如果你能指点一下我哪里做错了,我将不胜感激。

private static void Main(string[] args)
    {
        //create a socket
        //create a end point to listen on
        //bind
        //listen
        //accept the socket on a new socket
        //receive
        //store the connection in a list
        //ping back on their socket
        //go back to listening state
        Console.Title = " TCP NAT PT Server";
        StartServer();
    }
    private static void StartServer()
    {
        Thread ListenThread = new Thread(new ThreadStart(Listen));
        ListenThread.Start();
        Console.WriteLine("ListenThread: " + ListenThread.ThreadState);
    }
    private static void Listen()
    {
        try
        {
            server.Bind(ep);
            server.Listen(0);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
        while (true)
        {
            try
            {
                Socket handler = server.Accept();
                Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientCommunication));
                clientThread.Start((object)handler);
                Console.WriteLine("ReceiveThread: " + clientThread.ThreadState);
                string rstr = handler.RemoteEndPoint.ToString();
                string[] rdata = rstr.Split(':');
                IPEndPoint rep = new IPEndPoint(IPAddress.Parse(rdata[0]), int.Parse(rdata[1]));
                clients.Add(rep);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
    }
    private static void HandleClientCommunication(object Client)
    {
        Socket sock = (Socket)Client;
        byte[] data = new byte[1024];
        string str = string.Empty;
        while (true)
        {
            try
            {
                int rec = sock.Receive(data, SocketFlags.None);
                Array.Resize(ref data, rec);
                str = Encoding.ASCII.GetString(data);
                Console.WriteLine(sock.RemoteEndPoint.ToString() + " >> " + str);
                //Console.WriteLine(clients.Count);
                //Console.WriteLine(clients[0].Address + ":" + clients[0].Port);
                string temp = Encoding.ASCII.GetString(data);
                temp = "Echo: " + temp;
                data = Encoding.ASCII.GetBytes(temp);
                Console.WriteLine("Data.Length: " + temp.Length);
                for (int i = 0; i < clients.Count; i++)
                {
                    sock.SendTo(data, data.Length, SocketFlags.None, clients[i]);
                    //sock.Send(data, data.Length, SocketFlags.None);
                }
                data = new byte[1024];
            }
            catch (Exception e)
            {
                //socket error
                Console.WriteLine(e.Message);
            }
        }

多线程TCP服务器回显到所有客户端

问题在这一行:

 sock.SendTo(data, data.Length, SocketFlags.None, clients[i]);

根据SendTo方法doc:

如果您正在使用面向连接的协议,您必须首先通过调用Connect方法或建立远程主机连接使用accept方法接受传入的连接请求

您正在使用连接到端点a的套接字通过TCP向端点B发送字节,这实际上是不工作的。

因此,在listen方法中保留套接字列表,而不是在客户端保留端点:

while (true)
        {
            try
            {
                Socket handler = server.Accept();
                Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientCommunication));
                clientThread.Start((object)handler);
                Console.WriteLine("ReceiveThread: " + clientThread.ThreadState);
                clients.Add(handler);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }

并将发送消息的循环更改为:

for (int i = 0; i < clients.Count; i++)
{
    clients[i].Send(data);
}

只是一个提示:为了避免错误,您需要在客户端套接字接近时从clients列表中删除项目。