How to create multi threading socket server C#?

128 Views Asked by At

I have a WinForms application C#. In here, I used TcpClient/Socket and NetworkStream. I have created multiple thread to handle sending/receiving from client/server. Assuming I'm forced to use TcpClient/Socket, I won't use other libraries or third-party.

I can initiate multiple threads, and manage server/client connection in each thread. At the beginning, when I initialize (press start button), can send/receive data between client/server.

For example: I have 2 servers/ports, they will listening connections from the client side. Server A: 192.168.10.1/5555 Server B: 192.168.10.1/6666

After initialization, I received 2 connections from client to server. They're connected normal between client/server in each Thread. And some data send/receive at the beginning working well also, assuming server sending "Hello", and client reply "Ok. I'm fine", this way happened on separate threads, not overlapping each other. 192.168.10.1/5555 - 10.10.10.1/34546 192.168.10.1/6666 - 10.10.10.1/54632

After that, I proceeded to manually send data from server A 192.168.10.1/5555 to client 10.10.10.1/34546. For server A works normally, the client 10.10.10.1/34546 can receive data. But when I send information from server B 192.168.10.1/6666 to client 10.10.10.1/54632, It doesn't work although before that it received normal data at initialization. I don't know what's happened with my case. It works well when initialized, can send/receive on each connection between client/server. After that, messages can still be sent only in ServerA, ServerB can no longer send

public class Conn
{
    private TcpListener listener;
    private Socket socket;
    private NetworkStream stream;

    public TcpListener CListener
    {
        get { return listener; }
        set { listener = value; }
    }
    public Socket CSocket
    {
        get { return socket; }
        set { socket = value; }
    }
    public NetworkStream CStream
    {
        get { return stream; }
        set { stream = value; }
    }
}
private List<Conn> conn_list = null;
private async void _start_multi(Conn connection, TcpListener listener_multi, Socket socket_multi, NetworkStream stream_multi, string _ip, int _port)
{
    try
    {
        listener_multi = new TcpListener(IPAddress.Parse(_ip), _port);
        connection.CListener = listener_multi; //create listener
        listener_multi.Start();
        socket_multi = listener_multi.AcceptSocket();
        connection.CSocket = socket_multi; //create socket
        socket_multi.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
        socket_multi.SendTimeout = 180000;
        socket_multi.ReceiveTimeout = 180000;
        stream_multi = new NetworkStream(socket_multi);
        connection.CStream = stream_multi; //create stream
        while (true)
        {
            byte[] myReadBuffer = new byte[1024 * 5];
            int numberOfBytesRead = 0;
        rec_continute:
            numberOfBytesRead = stream_multi.Read(myReadBuffer, 0, myReadBuffer.Length);
            byte[] bytes_real = new byte[numberOfBytesRead];
            Buffer.BlockCopy(myReadBuffer, 0, bytes_real, 0, numberOfBytesRead);
            if (bytes_real.Length != 0)
            {
                byte[] msg_temp = Encoding.ASCII.GetBytes(Encoding.ASCII.GetString("HELLO"));
                stream_multi.Write(msg_temp, 0, msg_temp.Length);
                stream_multi.Flush();
                goto rec_continute;
            }
            if (bytes_real.Length == 0)
            {
                break;
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show("Warning" + ex.Message);
    }
}
private void bt_turnon_multi_Click(object sender, EventArgs e)
{
        dgv_multi_ip.Rows.Add("192.168.10.1", "5555");
        dgv_multi_ip.Rows.Add("192.168.10.1", "6666");
        for (int i = 0; i < dgv_multi_ip.Rows.Count; i++)
        {
            var ip = dgv_multi_ip.Rows[i].Cells[0].Value.ToString();
            var port = int.Parse(dgv_multi_ip.Rows[i].Cells[1].Value.ToString());
            var connection = conn_list[i];
            TcpListener listener_multi = null;
            Socket socket_multi = null;
            NetworkStream stream_multi = null;
            System.Threading.Thread thread = new System.Threading.Thread(() =>
            {
                _start_multi(connection, listener_multi, socket_multi, stream_multi, ip, port);
            });
            thread.Start();
        }
}
private async Task send_msg_multi(Conn connection)
{
    byte[] messageBytes = Encoding.ASCII.GetBytes(Encoding.ASCII.GetString("ARE YOU OK?"));
    try
    {
        connection.CStream.Write(messageBytes, 0, messageBytes.Length);
        connection.CStream.Flush();
        return;
    }
    catch (Exception ex)
    {
        MessageBox.Show("Can not send msg" + ex.Message);
    }
}
private async void bt_send_multi_Click(object sender, EventArgs e)
{
                for (int i = 0; i < conn_list.Count; i++)
                {
                        await send_msg_multi(conn_list[i]);
                }
}

So, any idea for this, share with me. Thanks!

1

There are 1 best solutions below

5
Marc Gravell On

Writing a decent socket server is hard; the best answer I can give here is "don't" - Kestrel (the asp.net web server) can act as a socket server, including full connection and buffer management build on an async core, leaving you just needing to write the actual protocol code. An example of this is given in this redis-like server implementation, with more info in this 4 part blog series