【问题标题】:Multi Threaded TCP Server Echo back to all clients多线程 TCP 服务器回显给所有客户端
【发布时间】:2016-10-28 01:16:12
【问题描述】:

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

客户端可以通过任何方式正常连接并聊天和接收回显,但取决于连接的数量,它会根据连接的客户端数量回显给发送消息的同一客户端。例如,3 个客户端连接客户端 2 发送一个 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);
            }
        }

【问题讨论】:

    标签: c# multithreading sockets tcp server


    【解决方案1】:

    问题出在这一行:

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

    根据SendTo method doc

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

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

    因此,与其在客户端中保留端点,不如在监听方法中保留一个套接字列表:

    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 列表中删除项目。

    【讨论】:

    • 很有趣,我在躺在床上思考我做错了什么后一个小时就做到了,并在大约 30 秒内让它工作。也感谢您的帮助。至少其他人可以从中获得一些用处,我会投票但我不能=/
    • 哈哈,有时会发生,尤其是当你需要睡觉的时候:))
    猜你喜欢
    • 2019-04-18
    • 2016-09-26
    • 2014-03-04
    • 1970-01-01
    • 1970-01-01
    • 2020-08-27
    • 2015-08-29
    • 1970-01-01
    • 2014-12-21
    相关资源
    最近更新 更多