C# TCP Server combining received data

后端 未结 1 999
走了就别回头了
走了就别回头了 2021-01-24 23:12

I\'m working on a rough TCP Server/Client. It works like this: Client sends message to server > Server sends all user data to each client. I have this in a loop as I\'m going to

相关标签:
1条回答
  • 2021-01-24 23:48

    This is because the TCP/IP protocol provides the stream of the data (bytes). If the strings are not separated explicitly, they are "concatenated" because of "streaming".

    It is required to "join" the messages using the "separator" when sending and "split" the messages using the "separator" when receiving. One of the following alternatives could be considered to implement the "separator" concept:

    • Introduce the "end-of-the-message" marker.
    • Introduce the message header which contains the length of the message.

    The small article, TCP/IP client-server application: exchange with string messages, may be useful to understand the mentioned alternatives.

    Update

    I would like to recommend implementing the "messaging" appropriately.

    Although it seems there is no the reason to compare the source code because it of its principal flaw (lack of "messaging" mechanism), the source code I have used to test the Client and the Server is attached.

    Client

    using System;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    
    internal sealed class Program
    {
        private const int Port = 100;
        private readonly Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        private bool hasLoggedin;
        private int dataSent;
    
        public static void Main()
        {
            var client = new Program();
            client.ConnectToServer();
            client.Exit();
        }
    
        private void ConnectToServer()
        {
            int attempts = 0;
    
            while (!clientSocket.Connected)
            {
                try
                {
                    attempts++;
                    string ip = "127.0.0.1";
                    Console.WriteLine("Port[default]: " + Port);
                    Console.WriteLine("Connection attempt to " + ip + ": " + attempts + " attempts");
                    var address = IPAddress.Parse(ip);
                    clientSocket.Connect(address, Port);
                }
                catch (SocketException e)
                {
                    Console.Clear();
                    Console.WriteLine(e.Message);
                    Console.ReadLine();
                }
            }
    
            Console.WriteLine("Connected!");
            SendLoginPacket();
        }
    
        private void SendLoginPacket()
        {
            if (hasLoggedin == false)
            {
                SendString("newuser:" + Guid.NewGuid());
                hasLoggedin = true;
            }
    
            RequestLoop();
        }
    
        private void RequestLoop()
        {
            while (true)
            {
                SendData();
                ReceiveResponse();
            }
        }
    
        private void Exit()
        {
            clientSocket.Shutdown(SocketShutdown.Both);
            clientSocket.Close();
        }
    
        private void SendData()
        {
            const string Data = "username:100|200";
            SendString(Data);
        }
    
        private void SendString(string text)
        {
            byte[] buffer = Encoding.ASCII.GetBytes(text);
            Console.WriteLine("Sent: " + text);
            clientSocket.Send(buffer, 0, buffer.Length, SocketFlags.None);
            dataSent++;
            Console.WriteLine(dataSent);
        }
    
        private void ReceiveResponse()
        {
            var buffer = new byte[2048];
            int received = clientSocket.Receive(buffer, SocketFlags.None);
            if (received == 0)
            {
                return;
            }
    
            var data = new byte[received];
            Array.Copy(buffer, data, received);
            string text = Encoding.ASCII.GetString(data);
    
            if (text.Contains("newuser:"))
            {
                string str = text.Replace("newuser:", string.Empty);
                Console.WriteLine(str + " has joined the game.");
            }
    
            Console.WriteLine("Clients connected.");
        }
    }
    

    Server

    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    
    internal sealed class Program
    {
        private const int BufferSize = 2048;
        private const int Port = 100;
        private readonly List<Socket> clientSockets = new List<Socket>();
        private readonly byte[] buffer = new byte[BufferSize];
        private readonly List<Player> players = new List<Player>();
        private Socket serverSocket;
        private Socket current;
        private int dataSent;
    
        public static void Main()
        {
            var program = new Program();
            program.SetupServer();
            Console.ReadLine();
            program.CloseAllSockets();
        }
    
        private void SetupServer()
        {
            Console.WriteLine("Setting up server...");
            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            serverSocket.Bind(new IPEndPoint(IPAddress.Any, Port));
            serverSocket.Listen(5);
            serverSocket.BeginAccept(AcceptCallback, null);
            Console.WriteLine("Server setup complete");
            Console.WriteLine("Listening on port: " + Port);
        }
    
        private void CloseAllSockets()
        {
            foreach (Socket socket in clientSockets)
            {
                socket.Shutdown(SocketShutdown.Both);
                socket.Close();
            }
    
            serverSocket.Close();
        }
    
        private void AcceptCallback(IAsyncResult AR)
        {
            Socket socket;
    
            try
            {
                socket = serverSocket.EndAccept(AR);
            }
            catch (ObjectDisposedException) // I cannot seem to avoid this (on exit when properly closing sockets)
            {
                return;
            }
    
            clientSockets.Add(socket);
            socket.BeginReceive(buffer, 0, BufferSize, SocketFlags.None, ReceiveCallback, socket);
            Console.WriteLine("Client connected: " + socket.RemoteEndPoint);
            serverSocket.BeginAccept(AcceptCallback, null);
        }
    
        private void ReceiveCallback(IAsyncResult AR)
        {
            current = (Socket)AR.AsyncState;
            int received = 0;
    
            try
            {
                received = current.EndReceive(AR);
            }
            catch (SocketException)
            {
                Console.WriteLine("Client forcefully disconnected");
                current.Close(); // Dont shutdown because the socket may be disposed and its disconnected anyway
                clientSockets.Remove(current);
                return;
            }
    
            byte[] recBuf = new byte[received];
            Array.Copy(buffer, recBuf, received);
            string text = Encoding.ASCII.GetString(recBuf);
    
            if (text.Contains("newuser:"))
            {
                string newuser = text.Replace("newuser:", string.Empty);
                Player newPlayer = new Player(newuser, current.RemoteEndPoint.ToString());
                players.Add(newPlayer);
                SendString("newuser:" + newuser);
                Console.WriteLine(newuser + " has joined the game.");
            }
            else
            {
                // This is where the client text gets mashed together.
                Console.WriteLine(text);
            }
    
            current.BeginReceive(buffer, 0, BufferSize, SocketFlags.None, ReceiveCallback, current);
        }
    
        private void SendString(string message)
        {
            try
            {
                byte[] data = Encoding.ASCII.GetBytes(message.ToString());
                current.Send(data);
                // current.BeginReceive(buffer, 0, BufferSize, SocketFlags.None, ReceiveCallback, current);
                dataSent++;
            }
            catch (Exception ex)
            {
                Console.WriteLine("Client disconnected!" + ex.Message);
            }
            Console.WriteLine(dataSent);
        }
    }
    
    internal sealed class Player
    {
        public Player(string newuser, string toString)
        {
        }
    }
    

    Client output

    Port[default]: 100
    Connection attempt to 127.0.0.1: 1 attempts
    Connected!
    Sent: newuser:6b06f0a6-bdb0-4471-ac58-fa9c490b7555
    1
    Sent: username:100|200
    2
    6b06f0a6-bdb0-4471-ac58-fa9c490b7555username:100|200 has joined the game.
    Clients connected.
    Sent: username:100|200
    3
    

    Server output

    Setting up server...
    Server setup complete
    Listening on port: 100
    Client connected: 127.0.0.1:1082
    1
    6b06f0a6-bdb0-4471-ac58-fa9c490b7555username:100|200 has joined the game.
    username:100|200
    
    0 讨论(0)
提交回复
热议问题