0

I'm trying to train myself and i'm currently building a small Tcp server / client.

I have for the moment 3 small classes that connect, listen for clients and listen to messages. Here are the 3 classes :

public class ServersLauncher
{

    #region Main
    public static void Main(string[] args)
    {
        ServersLauncher sl = new ServersLauncher();
        Console.ReadLine();
        sl._udpServer?.Dispose();
        sl._tcpServer?.Dispose();
    }
    #endregion Main

    private UdpServer _udpServer;
    private TcpServer _tcpServer;

    private ServersLauncher()
    {
        _tcpServer = new TcpServer();
        Socket sc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 25004);
        sc.Bind(localEndPoint);
        IPEndPoint distantEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 25000);
        sc.Connect(distantEndPoint);
        while (!sc.Connected)
            Thread.Sleep(1000);
        byte[] buffer = Utility.ConvertMessage("Hell world !");
        sc.Send(buffer, buffer.Length, SocketFlags.None);
        sc.Close();
    }

}

On top is the server launcher, it launches the server, create the client and send a message.

public class TcpServer : IDisposable
{

    private readonly int _portTcp = 25000;
    private Socket _socket;
    private Thread _connectionsThread;
    private List<TcpClient> _clients;

    public TcpServer()
    {
        _clients = new List<TcpClient>();

        _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), _portTcp);
        _socket.Bind(endPoint);
        _connectionsThread = new Thread(new ThreadStart(ListenConnections));
        _connectionsThread.Start();
    }

    public void Dispose()
    {
        _connectionsThread.Abort();
        for(int i = 0; i < _clients.Count; i++)
        {
            _clients[i].Dispose();
        }
        _socket.Close();
    }

    private void ListenConnections()
    {
        _socket.Listen(100);
        while (true)
        {
            Socket clientSocket = _socket.Accept();
            _clients.Add(new TcpClient(clientSocket));
        }
    }

}

On top is the TcpServer that listen to the connections and create a client interface when one client connect.

public class TcpClient : IDisposable
{

    private Socket _client;
    private Thread _receiverThread;

    public TcpClient(Socket client)
    {
        _client = client;
        _receiverThread = new Thread(ReceiveMessage);
        _receiverThread.Start();
    }

    public void Dispose()
    {
        _receiverThread.Abort();
    }

    private void ReceiveMessage()
    {
        while (true)
        {
            byte[] buffer = new byte[1024];
            _client.Receive(buffer);
            Utility.DisplayThread("A message has been received : " + Encoding.ASCII.GetString(buffer).Trim());
        }
    }

}

And here is the TcpClient that store the socket client and listen for messages. Nothing that complicated but i have an issue with the reading of the message. Right now, if i launch the program, the client connect but then... non stop messages ! I receive one "Hell world" then empty messages. I read the documentation of the Receive method for the Socket and it seems that it should block and wait for a message to pursue is routine. Do i do something wrong somewhere ? Do i need to flush the stream from the client before disconnecting ? Thanks for helping !

Kamigaku
  • 61
  • 1
  • 9
  • 2
    What you need is to take some time to _study_ how network works, before you attempt to write networking code. A good place to start is the [Winsock Programmer’s FAQ](http://tangentsoft.net/wskfaq/). It's not .NET specific, but the .NET API is just a thin layer over Winsock, and even much of the information you need and which is documented there is more about the protocols, TCP and UDP, commonly used on the Internet as it is about Winsock specifically. – Peter Duniho Jun 12 '17 at 18:03
  • 2
    In your code above, the problem is that you don't bother to look at the value returned by `Receive()`. When it returns 0, the connection has been disconnected and you should stop trying to receive. When it returns a value other than 0, you should actually _use_ that value to determine how many bytes were _actually_ sent, so that you make sure you process only the bytes in your buffer that were just received. – Peter Duniho Jun 12 '17 at 18:03
  • Possible duplicate of https://stackoverflow.com/questions/19221199/c-sharp-socket-receive-continuously-receives-0-bytes-and-does-not-block-in-the-l – Peter Duniho Jun 12 '17 at 18:08
  • See also https://stackoverflow.com/questions/1395026/socket-endread-0-bytes-means-disconnected, https://stackoverflow.com/questions/5868893/why-socket-reads-0-bytes-when-more-was-available, and https://stackoverflow.com/questions/22240387/received-data-buffer-always-empty-after-calling-sockets-receiveasync-call – Peter Duniho Jun 12 '17 at 18:12
  • Well, my bad, shoud have looked for the documentation more in depth. Thanks! – Kamigaku Jun 12 '17 at 18:16

2 Answers2

3

Reason for receiving empty messages is that your client socket remains connected.

You can wait to receive more messages with your client, if that is what you want try this:

 private void ReceiveMessage()
        {
            while (true) {
                if(_client.Available > 0) {
                    byte[] buffer = new byte[1024];
                    _client.Receive(buffer);
                    Console.WriteLine("A message has been received : " + Encoding.ASCII.GetString(buffer));
                }
            }
        }

if(_client.Available > 0) checks if there are any number of bytes of data received from the network and available to be read.

Update me on how it goes;

Good luck;

sBanda
  • 379
  • 2
  • 8
0

Hmm, I'm not sure what behaviour you expect to see.

You create a new ServerLauncher and then when doing so, you do the following:

sc.Connect(distantEndPoint);
while (!sc.Connected)
   Thread.Sleep(1000);
byte[] buffer = Utility.ConvertMessage("Hell world !");
sc.Send(buffer, buffer.Length, SocketFlags.None);
sc.Close();

This connects, waits until connected, sends a message and then closes.

Your main method then calls Console.ReadLine();...

If your server is closed, no more messages will come through. Remove the sc.Close(); line (or only call it when some flag is called like X)

Perhaps you should create a loop and send message from the loop, or better, pass messages from the commandline.

pookie
  • 3,796
  • 6
  • 49
  • 105