Jamesst20
Jamesst20

Reputation: 396

C# Socket(server) wont receive any datas

I am trying to make an advanced chat in C#. I am not new to programming but it is close to my first TCP chat.

The problem is that my Socket (server) looks to not receive any datas. In my void ReceiveDataListener which is a BackgroundWorker, I added some Console.WriteLine(); to check where it locks and it only display the first Console.WriteLine("Receive Data Listener 0"). I know it is normal that Socket.Receive() lock until some datas are received but it seems to stay locked even if I send datas.

I also want to add that my event onClientConnect and onClientDisconnect are invoked fine so I know the clients connects fine.

Here is the code of my Server class :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.ComponentModel;
using System.Threading;

namespace JAChat.Library
{
    class SocketServer
    {
        private Socket socket;
        private BackgroundWorker bwSocketConnectListener;
        private BackgroundWorker bwCheckIfConnected;
        private BackgroundWorker bwReceiveDataListener;
        private List<ClientManager> clientsList;

        #region Constructor
        public SocketServer(int port)
        {
            clientsList = new List<ClientManager>();

            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Bind(new IPEndPoint(IPAddress.Any, port));
            socket.Listen(100);

            bwSocketConnectListener = new BackgroundWorker();
            bwSocketConnectListener.DoWork += new DoWorkEventHandler(ListenSocketConnection);
            bwSocketConnectListener.RunWorkerAsync();

            bwCheckIfConnected = new BackgroundWorker();
            bwCheckIfConnected.DoWork += CheckIfClientStillConnectedThread;
            bwCheckIfConnected.RunWorkerAsync();

            bwReceiveDataListener = new BackgroundWorker();
            bwReceiveDataListener.DoWork += ReceiveDataListener;
            bwReceiveDataListener.RunWorkerAsync();
        }
        #endregion

        #region Getter
        public List<ClientManager> connectedClients
        {
            get
            {
                return clientsList;
            }
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Parse and send the command object to targets
        /// </summary>
        public void sendCommand(Command cmd)
        {
            BackgroundWorker test = new BackgroundWorker();
            test.DoWork += delegate {
                foreach(ClientManager cManager in clientsList){
                    cManager.sendCommand(cmd);
                }
            };
            test.RunWorkerAsync();
        }

        /// <summary>
        /// Disconnect and close the socket
        /// </summary>
        public void Disconnect()
        {
            socket.Disconnect(false);
            socket.Close();
            socket = null; //Stop some background worker
        }
        #endregion

        #region Private Methods
        private void ListenSocketConnection(object sender, DoWorkEventArgs e)
        {
            while (socket != null)
            {
                //Get and WAIT for new connection
                ClientManager newClientManager = new ClientManager(socket.Accept());
                clientsList.Add(newClientManager);
                onClientConnect.Invoke(newClientManager);
            }
        }

        private void CheckIfClientStillConnectedThread(object sender, DoWorkEventArgs e){
            while(socket != null){
                for(int i=0;i<clientsList.Count;i++){
                    if(clientsList[i].socket.Poll(10,SelectMode.SelectRead) && clientsList[i].socket.Available==0){
                        clientsList[i].socket.Close();
                        onClientDisconnect.Invoke(clientsList[i]);
                        clientsList.Remove(clientsList[i]);
                        i--;                        
                    }
                }
                Thread.Sleep(5);
            }
        }

        private void ReceiveDataListener(object sender, DoWorkEventArgs e){
            while (socket != null){
                Console.WriteLine("Receive Data Listener 0");
                //Read the command's Type.
                byte[] buffer = new byte[4];
                int readBytes = this.socket.Receive(buffer, 0, 4, SocketFlags.None);
                Console.WriteLine("Receive Data Listener 1");
                if (readBytes == 0)
                    break;
                Console.WriteLine("Receive Data Listener 2");
                CommandType cmdType = (CommandType)(BitConverter.ToInt32(buffer, 0));
                Console.WriteLine("Receive Data Listener 3");

                //Read the sender IP size.
                buffer = new byte[4];
                readBytes = this.socket.Receive(buffer, 0, 4, SocketFlags.None);
                if (readBytes == 0)
                    break;
                int senderIPSize = BitConverter.ToInt32(buffer, 0);

                //Read the sender IP.
                buffer = new byte[senderIPSize];
                readBytes = this.socket.Receive(buffer, 0, senderIPSize, SocketFlags.None);
                if (readBytes == 0)
                    break;
                IPAddress cmdSenderIP = IPAddress.Parse(System.Text.Encoding.ASCII.GetString(buffer));

                //Read the sender name size.
                buffer = new byte[4];
                readBytes = this.socket.Receive(buffer, 0, 4, SocketFlags.None);
                if (readBytes == 0)
                    break;
                int senderNameSize = BitConverter.ToInt32(buffer, 0);

                //Read the sender name.
                buffer = new byte[senderNameSize];
                readBytes = this.socket.Receive(buffer, 0, senderNameSize, SocketFlags.None);
                if (readBytes == 0)
                    break;
                string cmdSenderName = System.Text.Encoding.Unicode.GetString(buffer);

                //Read target IP size.
                string cmdTarget = "";
                buffer = new byte[4];
                readBytes = this.socket.Receive(buffer, 0, 4, SocketFlags.None);
                if (readBytes == 0)
                    break;
                int targetIPSize = BitConverter.ToInt32(buffer, 0);

                //Read the command's target.
                buffer = new byte[targetIPSize];
                readBytes = this.socket.Receive(buffer, 0, targetIPSize, SocketFlags.None);
                if (readBytes == 0)
                    break;
                cmdTarget = System.Text.Encoding.ASCII.GetString(buffer);

                //Read the command's MetaData size.
                string cmdMetaData = "";
                buffer = new byte[4];
                readBytes = this.socket.Receive(buffer, 0, 4, SocketFlags.None);
                if (readBytes == 0)
                    break;
                int metaDataSize = BitConverter.ToInt32(buffer, 0);

                //Read the command's Meta data.
                buffer = new byte[metaDataSize];
                readBytes = this.socket.Receive(buffer, 0, metaDataSize, SocketFlags.None);
                if (readBytes == 0)
                    break;
                cmdMetaData = System.Text.Encoding.Unicode.GetString(buffer);

                //Create the command object
                Command cmd = new Command(cmdType, cmdSenderIP, cmdSenderName, IPAddress.Parse(cmdTarget), cmdMetaData);
                this.onCommandReceived(cmd);
            }
            Console.WriteLine("Receive data listener closed");
        }
        #endregion

        #region Events
        public delegate void OnClientConnectEventHandler(ClientManager client);
        /// <summary>
        /// Events invoked when a client connect to the server
        /// </summary>
        public event OnClientConnectEventHandler onClientConnect = delegate { };

        public delegate void OnClientDisconnectEventHandler(ClientManager client);
        /// <summary>
        /// Events invoked when a client disconnect from the server
        /// </summary>
        public event OnClientDisconnectEventHandler onClientDisconnect = delegate { };

        public delegate void OnCommandReceivedEventHandler(Command cmd);
        /// <summary>
        /// Events invoked when a command has been sent to the server
        /// </summary>
        public event OnCommandReceivedEventHandler onCommandReceived = delegate { };
        #endregion
    }
}

and here is the code that I use to test the server by sending datas :

clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        clientSocket.Connect("localhost", 2000);
        networkStream = new NetworkStream(clientSocket);


    //CommandType
    byte[] buffer = new byte[4];
    buffer = BitConverter.GetBytes(1);
    this.networkStream.Write(buffer, 0, 4);
    this.networkStream.Flush();

    //Sender IP + Size
    byte[] senderIPBuffer = Encoding.ASCII.GetBytes("192.54.67.8");
    buffer = new byte[4];
    buffer = BitConverter.GetBytes(senderIPBuffer.Length);
    this.networkStream.Write(buffer, 0, 4);
    this.networkStream.Flush();
    this.networkStream.Write(senderIPBuffer, 0, senderIPBuffer.Length);
    this.networkStream.Flush();

    //Sender Name + Size
    byte[] senderNameBuffer = Encoding.ASCII.GetBytes("James");
    buffer = new byte[4];
    buffer = BitConverter.GetBytes(senderNameBuffer.Length);
    this.networkStream.Write(buffer, 0, 4);
    this.networkStream.Flush();
    this.networkStream.Write(senderNameBuffer, 0, senderNameBuffer.Length);
    this.networkStream.Flush();

    //Command Target IP + Size
    byte[] targetIPBuffer = Encoding.ASCII.GetBytes("192.43.54.6");
    buffer = new byte[4];
    buffer = BitConverter.GetBytes(targetIPBuffer.Length);
    this.networkStream.Write(buffer, 0, 4);
    this.networkStream.Flush();
    this.networkStream.Write(targetIPBuffer, 0, targetIPBuffer.Length);
    this.networkStream.Flush();

    //Command MetaData + Size
    byte[] metaBuffer = Encoding.Unicode.GetBytes("Metadata contents");
    buffer = new byte[4];
    buffer = BitConverter.GetBytes(metaBuffer.Length);
    this.networkStream.Write(buffer, 0, 4);
    this.networkStream.Flush();
    this.networkStream.Write(metaBuffer, 0, metaBuffer.Length);
    this.networkStream.Flush();

Upvotes: 0

Views: 545

Answers (1)

huntharo
huntharo

Reputation: 2846

  1. SocketServer has a class-level variable named "socket"
  2. SocketServer's constructor creates a socket for listening on the specified port and saves this as the value of socket
  3. ListenSocketConnection is calling Socket.Accept (good) and keeping a list of connections
  4. ERROR: ReceiveDataListener is trying to read from the socket that is listening on the specified port instead of reading from the individual sockets that were returned by the Accept call in ListenSocketConnection

Note: the server throws an exception right on startup (for me at least) in ReceiveDataListener, before any client has even attempted to connect, since the socket reader worker immediately tries to read from a socket that is in the listen state.

Hope that helps - Harold

Upvotes: 1

Related Questions