TCP Socket在C#中收到错误的数据

时间:2018-04-08 13:20:22

标签: c# file sockets tcp send

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

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

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编码。这是我的代码:

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

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.");
        }
    }

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

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;  
        }
    }

控制台输出: enter image description here

是的,对不起,它没有评论或有点凌乱。只是一个爱好项目,没有专业。忽略&#34;希特勒&#34;东西。它只是我的驱动器上的一些随机垃圾。不是纳粹或任何东西:)。

1 个答案:

答案 0 :(得分:1)

我的建议是利用TCPListener中提供的TCPClientSystem.Net.Sockets类,它们真正简化了TCP/IP上的发送消息。

服务器端你需要这样的东西:

  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();
            }
        }
    }

显然,你会想要让它适应你的程序结构。我从here获取了这个,但稍微编辑了一下。

在您的客户端,您希望使用以下内容:

    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();
        }
    }

}

同样,这需要适应您的结构,我从here获取它。如果您不希望服务器做出响应,则可以删除所有响应内容。

这两个类非常有弹性并且抽象出所有复杂的东西,数据缓冲区的大小也可以改变为你需要的任何大小。