无法使用 C# TCP 服务器和 C++ TCP 客户端接收消息

Can't receive messages with C# TCP server and C++ TCP client

我有一个 C# TCP 服务器和一个 C++ TCP 客户端(使用 winsock2)。我正在尝试发送多条消息,但只收到了第一条消息...

C# 服务器代码

IPAddress raw = IPAddress.Parse("127.0.0.1");
IPEndPoint ip = new IPEndPoint(raw, 7777);

Socket client = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
client.Bind(ip);
client.Listen(69);

Console.WriteLine("Waiting for connection.");
Socket conn = client.Accept();
Console.WriteLine("Got connection");

string message;
int bytesRecv;
byte[] recvBuf = new byte[100];

bytesRecv = conn.Receive(recvBuf);
Console.WriteLine("Received message, bytes: " + bytesRecv);
message = System.Text.Encoding.UTF8.GetString(recvBuf);
Console.WriteLine(message);
Array.Clear(recvBuf, 0, recvBuf.Length);

bytesRecv = conn.Receive(recvBuf);
Console.WriteLine("Received message, bytes: " + bytesRecv);
message = System.Text.Encoding.UTF8.GetString(recvBuf);
Console.WriteLine(message);
Array.Clear(recvBuf, 0, recvBuf.Length);

bytesRecv = conn.Receive(recvBuf);
Console.WriteLine("Received message, bytes: " + bytesRecv);
message = System.Text.Encoding.UTF8.GetString(recvBuf);
Console.WriteLine(message);
Array.Clear(recvBuf, 0, recvBuf.Length);

bytesRecv = conn.Receive(recvBuf);
Console.WriteLine("Received message, bytes: " + bytesRecv);
message = System.Text.Encoding.UTF8.GetString(recvBuf);
Console.WriteLine(message);
Array.Clear(recvBuf, 0, recvBuf.Length);

Console.ReadLine();

这是 C++ 代码

#pragma once

#include "pch.h"
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <iostream>
#include <string>
#include<winsock2.h>
#include <WS2tcpip.h>

#pragma (lib, "ws2_32.lib")

using namespace std;

int main()
{
        WSAData wsaData;
        SOCKADDR_IN addr;
        int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
        cout << "startup gave: " << result << endl;

        SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        addr.sin_family = AF_INET;
        addr.sin_port = htons(7777);
        addr.sin_addr.s_addr = inet_addr("127.0.0.1");

        result = connect(s, (SOCKADDR*)&addr, sizeof(addr));
        cout << "Connect gave: " << result << endl;

        int count = 0;
        char sendBuf[1024] = "Hello";
        int sendResult;
        sendResult = send(s, sendBuf, sizeof(sendBuf), 0);
        sendResult = send(s, sendBuf, sizeof(sendBuf), 0);
        sendResult = send(s, sendBuf, sizeof(sendBuf), 0);
        sendResult = send(s, sendBuf, sizeof(sendBuf), 0);
}

为什么只收到第一条消息?服务器正在接收一个 recv 语句中的所有字节,因此没有理由(据我所知)这不起作用。谢谢!

每个服务器的接收语句都收到 100 字节(发送的全部数量)。

sizeof returns 对象的大小。在这种情况下,并不是所有的对象都被实际使用,但 sizeof 并不关心。它总是 returns 对象的大小。随着

char sendBuf[1024] = "Hello";

sizeof(sendBuf) 无论使用多少个字符,总是 1024。这意味着

send(s, sendBuf, sizeof(sendBuf), 0);

发送 "Hello[=19=]" 以及其他 1018 个未指定的字节(由于 char sendBuf[1024] = "Hello"; 的初始化方式,很确定这将是所有空字符,但找不到标准引用来证明这一点。 ) 在发送缓冲区中。此代码重复 4 次,总共发送 4096 个字节。我的 .Net 不稳定,但是

byte[] recvBuf = new byte[100];
conn.Receive(recvBuf);

将接收最多 100 个字节。那是 Hello 和一大堆空字符。您必须阅读其中的 10.24 篇才能通过所有额外的空值找到下一个 Hello.

所以第一个

message = System.Text.Encoding.UTF8.GetString(recvBuf);

设法打印出 Hello,但接下来的三个只能看到 100 个字节的空字符。

解决方案:

只发送您需要发送的内容。

char sendBuf[1024] = "Hello";
sendResult = send(s, sendBuf, strlen(sendBuf), 0); // send all characters up to the 
                                                   // first null character

char sendBuf[] = "Hello"; // buffer will be sized to fit string(including null)
sendResult = send(s, sendBuf, sizeof(sendBuf), 0); 

警告:

TCP/IP 是一种流媒体协议。它没有单独消息的概念,并且会根据需要将对 send 的单独调用混搭成一个或多个数据包。这意味着第一次接收可能 return 所有四个 Hello

此外,接收方永远不知道他们将通过给定的 TCP 套接字读取接收到什么。一条消息可能已拆分为两个数据包以最大化吞吐量,并且这些数据包中的一个可能已被路由很远并且在客户端读取消息时不可用。

您将需要建立和使用通信协议来区分您的消息。发送字符串时,我更喜欢以 integer of known size 和字节序发送字符串的大小,然后发送字符串。接收方读取字符串的长度(并确保它在继续之前获得所有长度),然后读取长度字节(同样不多不少)以获取字符串。