TCP套接字在C#中接收到错误的数据 [英] TCP Socket recieves data wrong in C#

查看:49
本文介绍了TCP套接字在C#中接收到错误的数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将文件从一个套接字发送到另一个套接字.套接字在两个不同的应用程序(客户端应用程序和服务器应用程序)中运行.现在,在同一台计算机上进行测试时会发生这种情况.客户端准备好接收有关将发送给它的文件的第一个信息(例如,文件名和2056字节消息中的字节大小,以字节为单位)时,客户端首先将其发送到服务器.然后,每次准备接收新的2048文件内容缓冲区时,它都会发送一条消息.

I'm trying to send files from a Socket to another Socket. The sockets are running in two different applications, a client application and a server application. This is happening on the same machine now when testing it. The client first sends to the server when it is ready to receive first info about the file that will be sent to it like filename and file size in bytes in a 2056 bytes message. Then it sends a message each time it is ready to receive a new 2048 buffer of file content.

简而言之,这是每个文件的通信流程:

In short, this is the communication flow for each file:

client -"CLIENT_READY_TO_RECEIVE_FILE_INFO"-------> server
client <-"File name+file size of file coming next"-  server
client -"CLIENT_READY_TO_RECEIVE_CONTENT_BUFFER" -> server
client <-"2048 byte buffer of file content"-------- server
...the same flow is repeated until all files are sent to the client.

我的问题是,尽管我仔细检查了服务器是否正确发送了文件,但客户端接收到的文件信息消息错误.它们都使用ASCII编码.这是我的代码:

My problem is that the client receives the file info message wrong, although I have double checked that the server sends it corretly. They both use ASCII encoding. Here is my code:

客户端代码(接收文件):

Client code (receives the files):

private void fetchFilesThreadMethod()
    {
        

        String localHostName = Dns.GetHostName();
        IPAddress[] localIPs = Dns.GetHostAddresses(localHostName);
        IPAddress localIP = localIPs[2];
        int port = 1305;
        IPEndPoint localEP = new IPEndPoint(localIP,port);
        fetchFilesSocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
        fetchFilesSocket.Bind(localEP);
        fetchFilesSocket.Listen(1);
        fetchFilesSocket = fetchFilesSocket.Accept();

        while (true)
        {
            byte[] receivedFileInfo = new byte[2056];
            byte[] receivedFileCont = new byte[2048];
            byte[] comMessage = new byte[100];
            byte[] comMessageBytes;
            String fileInfoStr = String.Empty;
            String fileNameStr = String.Empty; ;
            String fileExtStr = String.Empty;
            String comMessageStr = String.Empty;
            String fileSizeStr = String.Empty;
            ulong fileSize = 0;
            ulong lastBytesSize = 0;

            comMessageStr = "CLIENT_READY_TO_RECEIVE_FILE_INFO";
            comMessageBytes = Encoding.ASCII.GetBytes(comMessageStr);
            for (int i = 0; i < comMessageBytes.Length; i++)
                comMessage[i] = comMessageBytes[i];
            Console.WriteLine("Bytes available to be flushed by client: " + fetchFilesSocket.Available);
            if (fetchFilesSocket.Available > 0)
            {
                Console.WriteLine(fetchFilesSocket.Available + " bytes flushed by client.");
                byte[] flusher = new byte[fetchFilesSocket.Available];
                fetchFilesSocket.Receive(flusher, 0, fetchFilesSocket.Available, SocketFlags.None);
            }
            fetchFilesSocket.Send(comMessage, 0, 100, SocketFlags.None);
            Console.WriteLine("Client sent ready to receive file info.");
            fetchFilesSocket.Receive(receivedFileInfo,0,2056, SocketFlags.None);
            fileInfoStr = Encoding.ASCII.GetString(receivedFileInfo);
            Console.WriteLine("Received file info:" + fileInfoStr);
            fileNameStr = fileInfoStr.Split(new String[] { "ENDN" }, StringSplitOptions.None)[0];
            Console.WriteLine("Received file name:" + fileNameStr);
            fileExtStr = fileNameStr.Split('.').Last();
            Console.WriteLine("Received file extension:" + fileExtStr);
            fileSizeStr = fileInfoStr.Split(new String[] {"ENDS"},StringSplitOptions.None)[0];
            fileSizeStr = fileSizeStr.Split(new String[] {"ENDN"},StringSplitOptions.None).Last();
            Console.WriteLine("File size string:" + fileSizeStr);
            fileSize = Convert.ToUInt64(fileSizeStr,10);
            Console.WriteLine("Received file size:" + fileSize);
            lastBytesSize = fileSize % 2048;
            ulong byteCount = 0;
            bool keepReceiving = true;
            ulong buffersReceived = 0;
            while (keepReceiving)
            {
                comMessageStr = "CLIENT_READY_TO_RECEIVE_CONTENT_BUFFER";
                comMessageBytes = Encoding.ASCII.GetBytes(comMessageStr);
                for (int i = 0; i < comMessageBytes.Length; i++)
                    comMessage[i] = comMessageBytes[i];
                fetchFilesSocket.Send(comMessage, 0, 100, SocketFlags.None);
                Console.WriteLine("Console sent ready to receive buffer message.");
                if (fileSize - byteCount >= 2048)
                {
                    fetchFilesSocket.Receive(receivedFileCont, 0, 2048, SocketFlags.None);
                    buffersReceived++;
                    Console.WriteLine("Buffers received:" + buffersReceived);
                    byteCount = byteCount + 2048;
                }
                else
                {
                    fetchFilesSocket.Receive(receivedFileCont, 0, 2048, SocketFlags.None);                        buffersReceived++;
                    byteCount = byteCount + 2048;
                    Console.WriteLine("Buffers received:" + buffersReceived);
                    keepReceiving = false;
                }
                Console.WriteLine("Bytes received " + byteCount + "/" + fileSize);
                //Console.WriteLine("Received bytes in current file:" + byteCount);
            }
            Console.WriteLine("File received.");
        }
    }

服务器代码(发送文件):

Server code (sends the files):

private void fetchThreadMethod(Object commandArgs)
    {
        if (fetchSocket == null)
        {
            fetchSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            int port = 1304;    
            IPEndPoint fetchSocketEP = new IPEndPoint(localIP,port);
            fetchSocket.Bind(fetchSocketEP);
        }
        if (!fetchSocket.Connected)
            try
            {
                fetchSocket.Connect(remoteIP, 1305);
                if (fetchSocket.Connected)
                    Console.WriteLine("Server fetch socket connected.");
            }catch(Exception e)
            {
                Console.WriteLine("Something went wrong when connecting the server fetch socket.");
            }
        FileCollector fCollector = new FileCollector();
        String userName = Environment.GetEnvironmentVariable("USERPROFILE");
        String targetDirectory = userName + "\\" + commandArgs;
        Console.WriteLine("Path sent to file collector:" + targetDirectory);
        fCollector.startFileCollector(targetDirectory);
        List<FileNode> collectedFiles = fCollector.getCollectedFiles();
        String comMessageStr = String.Empty;
        foreach (FileNode fNode in collectedFiles)
        {
            comMessageStr = String.Empty;
            byte[] sentFileInfo = new byte[2056];
            byte[] sentFileCont = new byte[2048];
            byte[] comMessage = new byte[100];
            String fileName = fNode.getFileName();
            String formattedFileInfo = fileName;
            formattedFileInfo += "ENDN";
            ulong fileSize = 0;
            FileStream fStream = null;
            try
            {
                fStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
                FileInfo fInfo = new FileInfo(fileName);
                fileSize = (ulong) fInfo.Length;
                if (fileSize == 0)
                    continue;
                formattedFileInfo += fileSize.ToString() + "ENDS";
            }
            catch (Exception e)
            {
                Console.WriteLine("Could not read from file:" + fileName);
                deniedAccessFiles.Add(fileName);
                continue;
            }
            byte[] fileInfoBytes = Encoding.ASCII.GetBytes(formattedFileInfo);
            for (int i = 0; i < fileInfoBytes.Length; i++)
                sentFileInfo[i] = fileInfoBytes[i];
            while (!comMessageStr.Equals("CLIENT_READY_TO_RECEIVE_FILE_INFO"))
            {
                Console.WriteLine("Server waiting for file info ready message from client.");
                fetchSocket.Receive(comMessage,0,100,SocketFlags.None);
                comMessageStr = Encoding.ASCII.GetString(comMessage);
                comMessageStr = comMessageStr.Substring(0,33);
                Console.WriteLine("Received parsed message from client:" + comMessageStr);
            }
            Console.WriteLine("Server received file info ready message from client.");
            comMessageStr = String.Empty;
            Console.WriteLine("formattedFileInfo:" + formattedFileInfo);
            Console.WriteLine("Sent file info:" + Encoding.ASCII.GetString(sentFileInfo));
            fetchSocket.Send(sentFileInfo, 0, 2056, SocketFlags.None);
            int readByte = 0;
            ulong byteCount = 0;
            ulong buffersSent = 0;
            while (readByte != -1)
            {
                if (byteCount == 2048)
                {
                    while (!comMessageStr.Equals("CLIENT_READY_TO_RECEIVE_CONTENT_BUFFER"))
                    {
                        Console.WriteLine("Server waiting for ready for buffer message from client.");
                        fetchSocket.Receive(comMessage, 100, SocketFlags.None);
                        comMessageStr = Encoding.ASCII.GetString(comMessage);
                        comMessageStr = comMessageStr.Substring(0,38);
                        Console.WriteLine("Received parsed message from client 1:" + comMessageStr);
                    }
                    Console.WriteLine("Server received ready for buffer message from client.");
                    fetchSocket.Send(sentFileCont, 0, 2048, SocketFlags.None);
                    comMessageStr = String.Empty;
                    buffersSent++;
                    Console.WriteLine("Buffers sent:" + buffersSent);
                    byteCount = 0;
                }
                else
                {
                    readByte = fStream.ReadByte();
                    if (readByte != -1)
                    {
                        sentFileCont[byteCount] = Convert.ToByte(readByte);
                        byteCount++;
                    }
                }   
            }
            while (!comMessageStr.Equals("CLIENT_READY_TO_RECEIVE_CONTENT_BUFFER"))
            {
                Console.WriteLine("Server waiting for ready for buffer message from client.");
                fetchSocket.Receive(comMessage, 100, SocketFlags.None);
                comMessageStr = Encoding.ASCII.GetString(comMessage);
                comMessageStr = comMessageStr.Substring(0, 38);
                Console.WriteLine("Received parsed message from client 2:" + comMessageStr);
            }
            Console.WriteLine("Server received ready for buffer message from client.");
            fetchSocket.Send(sentFileCont, 0, 2048, SocketFlags.None);
            buffersSent++;
            Console.WriteLine("Buffers sent:" + buffersSent);
            comMessageStr = String.Empty;  
        }
    }

控制台输出:

推荐答案

我的建议是利用 System.Net中提供的 TCPListener TCPClient 类.Sockets 确实简化了通过 TCP/IP 发送消息的过程.

My recommendation would be to utilise the TCPListener and TCPClient classes provided within System.Net.Sockets they really simplify sending messages over TCP/IP.

服务器端,您需要这样的内容:

Server side you need something like this:

  class MyTcpListener
    {
        public static void Listen()
        {
            TcpListener server = null;
            byte[] bytes = new byte[256];
            try
            {
                // Set the TcpListener on port 13000.
                const int port = 13000;
                IPAddress localAddr = IPAddress.Parse("127.0.0.1");
                // TcpListener server = new TcpListener(port);
                server = new TcpListener(localAddr, port);
                // Start listening for client requests.
                server.Start();
                // Enter the listening loop.
                while (true)
                {
                    Console.Write("Waiting for a connection... ");
                    // Perform a blocking call to accept requests.
                    // You could also user server.AcceptSocket() here.
                    TcpClient client = server.AcceptTcpClient();
                    Console.WriteLine("Connected!");
                    // Get a stream object for reading and writing
                    NetworkStream stream = client.GetStream();
                    int i;
                    // Loop to receive all the data sent by the client.
                    while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        // Translate data bytes to a ASCII string.
                        string data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
                        Console.WriteLine($"Received: {data}");
                        // Process the data sent by the client.
                        data = data.ToUpper();
                        byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
                        // Send back a response.
                        stream.Write(msg, 0, msg.Length);
                        Console.WriteLine($"Sent: {data}");
                    }
                    // Shutdown and end connection
                    client.Close();
                }
            }
            catch (SocketException e)
            {
                Console.WriteLine($"SocketException: {e}");
            }
            finally
            {
                // Stop listening for new clients.
                server?.Stop();
            }
        }
    }

显然,您需要根据程序的结构对其进行调整.我从此处获取,但稍加修改.

Obviously you'll want to adapt it to your program's structure. I took this from here but edited it slightly.

在您的客户端上,您想使用类似这样的东西:

And on your client side you want to use something like this:

    class MyTCPClient
    {
        static void Connect(String server, String message)
        {
            try
            {
                // Create a TcpClient.
                // Note, for this client to work you need to have a TcpServer 
                // connected to the same address as specified by the server, port
                // combination.
                int port = 13000;
                TcpClient client = new TcpClient(server, port);

                // Translate the passed message into ASCII and store it as a Byte array. Any encoding can be used as long as it's consistent with the server.
                byte[] data = System.Text.Encoding.ASCII.GetBytes(message);

                // Get a client stream for reading and writing.
                //  Stream stream = client.GetStream();
                NetworkStream stream = client.GetStream();

                // Send the message to the connected TcpServer. 
                stream.Write(data, 0, data.Length);
                Console.WriteLine($"Sent: {message}");

                // Receive the TcpServer.response. This is all optional and can be removed if you aren't recieving a response.
                // Buffer to store the response bytes.
                data = new byte[256];

                // String to store the response ASCII representation.

                // Read the first batch of the TcpServer response bytes.
                int bytes = stream.Read(data, 0, data.Length);
                string responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
                Console.WriteLine("Received: {responseData}");

                // Close everything.
                stream?.Close();
                client?.Close();
            }
            catch (ArgumentNullException e)
            {
                Console.WriteLine($"ArgumentNullException: {e}");
            }
            catch (SocketException e)
            {
                Console.WriteLine($"SocketException: {e}");
            }

            Console.WriteLine("\n Press Enter to continue...");
            Console.Read();
        }
    }

}

同样,这需要适应您的结构,我从

Again, this needs to be adapted to your structure and I took it from here. The response stuff can all be removed if you aren't expecting a response from your server.

这两个类非常灵活,可以抽象出所有复杂的东西,数据缓冲区的大小也可以更改为所需的大小.

These two classes are extremely resilient and abstract away all of the complicated stuff, the size of the data buffers can also be changed to whatever size you need.

这篇关于TCP套接字在C#中接收到错误的数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆