Kmaczek
Kmaczek

Reputation: 648

Clients and Server Listening for requests

I would like to know if my way of thinking is any good. Here is sitution:

What I want to do is to send requests from both client and server. Other side should recieve it.

Server code:

    public ServerHandler()
    {
        _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        _serverSocket.Bind(_ipLocal);
        _serverSocket.Listen(4);
        _serverSocket.BeginAccept(AcceptCallback, null);
    }

    private void AcceptCallback(IAsyncResult ar)
    {
        Socket socket = (Socket)ar.AsyncState;
        _clients.Add(socket);

        socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, RecieveCallback, socket);
        _serverSocket.BeginAccept(AcceptCallback, null);
    }

    private void RecieveCallback(IAsyncResult ar)
    {
        var socket = (Socket) ar.AsyncState;
        var recieved = socket.EndReceive(ar);
        var dataBuff = new byte[recieved];

        Array.Copy(_buffer, dataBuff, recieved);

        OnMessageRecieved(dataBuff);

        socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, RecieveCallback, socket);
    }

    private void Send(byte[] data, Socket socket)
    {
        socket.BeginSend(data, 0, data.Length, SocketFlags.None,
                SendCallback, socket);
    }

    private void SendCallback(IAsyncResult ar)
    {
        var socket = (Socket)ar.AsyncState;
        socket.EndSend(ar);
    }

    private void SendToAll(byte[] data)
    {
        foreach (var clientSocket in _clients)
        {
            Send(data, clientSocket);
            Debug.WriteLine("sent to: " + clientSocket.LocalEndPoint);
        }
    }

Client code:

    public ClientHandler()
    {
        _ipLocal = new IPEndPoint(IPAddress.Parse(ServerIp), Port);
    }

    public void ConnectLoop()
    {
        int attempts = 0;
        while (!_clientSocket.Connected)
        {
            try
            {
                attempts++;
                _clientSocket.BeginConnect(IPAddress.Parse(ServerIp), Port, ConnectCallback, null);
                _clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, RecieveCallback,
                                           _clientSocket);
            }
            catch (Exception)
            {
                Debug.WriteLine("Connection attempts: " + attempts);
            }
        }

        Debug.WriteLine("Connected");
    }

    private void ConnectCallback(IAsyncResult ar)
    {
        _clientSocket.EndConnect(ar);
    }

    private void RecieveCallback(IAsyncResult ar)
    {
        var socket = (Socket) ar.AsyncState;
        int recieved = _clientSocket.EndReceive(ar);
        var dataBuff = new byte[recieved];

        Array.Copy(_buffer, dataBuff, recieved);

        OnMessageRecieved(dataBuff);

        _clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, RecieveCallback, _clientSocket);
    }

    private void Send(byte[] data, Socket socket)
    {
        socket.BeginSend(data, 0, data.Length, SocketFlags.None,
                SendCallback, socket);
    }

    private void SendCallback(IAsyncResult ar)
    {
        var socket = (Socket)ar.AsyncState;
        socket.EndSend(ar);
    }

Will sth like this work?

EDIT1: Oh, and I want to do it through 1 socket. Client/server sending and recieveing on same socket. But there can be multiple clients sockets, but only 1 for pair client-server.

Upvotes: 0

Views: 1601

Answers (1)

andrew
andrew

Reputation: 1254

Without testing, your code looks alright however, you'll need to provide extra code to determine if you've got a whole message or not.

When you do a read, you may get one of the following scenarios:

  • Some of a message, but not all
  • exactly all of a message
  • all of a message plus some/all of another message
  • a socket error (disconnected etc).

There are a few generally accepted methods of determining what a whole message is:

  • delimiting your message so your receival code needs to look for the delimiters
  • A fixed message size with some sort of embedding to indicate if there are more messages
  • a variable message size but with a fixed "size" part which is transmitted first Ie say the first 4 bytes will indicate the size of the message. So you know you always need 4 bytes first to determine the length of the message; and then you know how much to process for the next message.

This SO post Chat service application has some more and links on processing messages.

Upvotes: 1

Related Questions