首页 > 解决方案 > c#网络客户端从TCP上的同一端口发送和接收数据

问题描述

我的任务是编写一个多线程客户端(有一个用于发送数据的线程和一个用于接收数据的不同线程)。出于某种原因,客户(为我的工作买单的人)坚持我使用相同的端口来发送(到服务器)和接收数据(从服务器)。据我所知,这不应该是不可能的,所以这就是我在这里的原因,看看我是否错了。

发送线程:

public void Send_msg()
{
    while (!GlobalVar.is_conn) { }
    try
    {
        socket = new Socket(AddressFamily.InterNetwork, GlobalVar._isTcp ? SocketType.Stream : SocketType.Dgram, GlobalVar._isTcp ? ProtocolType.Tcp : ProtocolType.Udp);
        IPEndPoint end_point = new IPEndPoint(Mul_ip, Mul_port);
        
        if (GlobalVar._isTcp)
        {
            socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseUnicastPort, true);
            socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
            socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, true);
        }
        else
        {
            socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(Mul_ip, IPAddress.Any));
        }
        socket.Bind(new IPEndPoint(IPAddress.Any,Mul_port));
        socket.Connect(end_point);
        GlobalVar.socketWasConfiged = true;
        while (!_shouldStop)
        {
            while (!Send_msg_queue.IsEmpty)
            { //while there are more messages to send
                Send_msg_queue.TryDequeue(out CM_msg send_msg);
                byte[] send_buff = Encoder(send_msg);
                try
                {
                    socket.Send(send_buff, SocketFlags.None);
                    GlobalVar.Is_Wd_Rec = false;
                }
                catch (Exception e)
                {
                    MessageBox.Show("Error while trying to send a message: " + e.Message, "Error");
                }
            }
        }
    }
    catch(Exception e)
    {
        MessageBox.Show("Error while trying to send a message: " + e.Message, "Error");
    }
    finally
    {
        socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true);
        socket.Close();
    }

可以看出,我打开一个套接字,通过 setSocketOption 更改其选项,然后绑定并连接到服务器,然后线程对一些队列进行采样并在发送消息时发送消息。同时应该接收消息的线程这样做:

        public void Receive_msg()
    {
        while (!GlobalVar.is_conn) { }
        try
        {
            while (!GlobalVar.socketWasConfiged) { }
            byte[] rec_buff = new byte[size];
            socket = new Socket(AddressFamily.InterNetwork,GlobalVar._isTcp? SocketType.Stream : SocketType.Dgram,GlobalVar._isTcp? ProtocolType.Tcp : ProtocolType.Udp);
            IPEndPoint end_point = new IPEndPoint(IPAddress.Any, Mul_port);
            if(GlobalVar._isTcp)
            {
                socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseUnicastPort, true);
                socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
                socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
                socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, true);
            }
            else
            {
                socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(Mul_ip, IPAddress.Any));
            }

            socket.Bind(end_point);
            socket.Connect(new IPEndPoint(Mul_ip, Mul_port));

            while (!_shouldStop)
            {
                size_rec = socket.Receive(rec_buff);
                GlobalVar.Counter_auto = GlobalVar.Counter_auto + 1;
                Receive_msg_queue.Enqueue(Decoder(rec_buff));
                // if a message was recieved than there is a connection to the unit, so we make Is_Wd_Rec true
                GlobalVar.Is_Wd_Rec = true;
            }
        }
        catch (Exception e)
        {
            MessageBox.Show("An error occur while trying to receive a message: " + e.Message);
        }
        finally
        {
            socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true);
            socket.Close();
        }
    }

可以看出,监听线程一直等到某个 globalVar 为真(所以我们不会得到并发的套接字绑定),然后它初始化套接字并尝试绑定/连接到服务器。一旦它尝试连接,我就会得到一个异常,它无法连接到已经连接的套接字。

有什么办法可以解决这个问题吗?还是我应该告诉客户端服务器应该写入不同的端口?

标签: c#multithreadingsocketstcp

解决方案


推荐阅读