0

我一直在寻找一种使用 Winsock2 通过 Windows 套接字发送整数的方法。我已经查看了人们在 stackoverflow 上提出的大多数问题,如果不是全部的话。

这是我为客户端发送的整数:

struct struct_var
{
    int Packet;
    int Number;
};

struct_var *arraystruct;

arraystruct = (struct_var *) malloc(sizeof(struct_var));
(*arraystruct).Packet = 100;
(*arraystruct).Number = 150;
int bytes = send(client,(char*)arraystruct,sizeof(*arraystruct),0);`

我也尝试使用以下方式发送:

int int_data = 4;
int bytes = send(server, (char*) &int_data, sizeof(int), 0);`

这是在另一个stackoverflow问题上推荐的 这是接收方,也被推荐:

int int_data;
int bytes = recv(server, (char*) &int_data, sizeof(int), 0);
cout << int_data;`

当我运行这些时,我从命令行得到的输出是:-858993460

有谁知道为什么会这样?

我还希望它具有正确的字节顺序,因为这将通过多种计算机发送。提前感谢谁能帮助我

完整的服务器代码:

int main() {
WSADATA wsaData;
WORD version;
int error;

version = MAKEWORD(2, 0);

error = WSAStartup(version, &wsaData);

if ( error != 0 )
{
    return FALSE;
}

if ( LOBYTE( wsaData.wVersion ) != 2 ||
     HIBYTE( wsaData.wVersion ) != 0 )
{
    WSACleanup();
    return FALSE;
}


SOCKET server;

server = socket(AF_INET, SOCK_STREAM, 0);

sockaddr_in sin;

sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(5555);

if (bind( server, (SOCKADDR*)&sin, sizeof(sin) ) == SOCKET_ERROR ){
    DWORD ec=WSAGetLastError();
    cerr << hex << "bind ERROR" << ec << endl;
    return FALSE;
}

if ( listen( server, SOMAXCONN ) == SOCKET_ERROR ) {
    DWORD ec=WSAGetLastError();
    cerr << hex << "listen ERROR" << ec << endl;
    return FALSE;
}

SOCKET client;
int length;

    while(1) {

    if ( listen( server, SOMAXCONN ) == SOCKET_ERROR ) {
    DWORD ec=WSAGetLastError();
    cerr << hex << "listen ERROR" << ec << endl;
    return FALSE;
    }

    length = sizeof sin;
    client = accept( server, (SOCKADDR*)&sin, &length );
    cout << "Client connected" << endl;
    cout << "Sending Instructions..." << endl;

    int int_data;
    int bytes;

    bytes = recv(client, (char*) &int_data, sizeof(int), 0);

    cout << int_data << endl;
}

}

}

完整的客户代码:

int main() {

WSADATA wsaData;
WORD version;
int error;

version = MAKEWORD(2, 0);

error = WSAStartup(version, &wsaData);

if ( error != 0 )
{
    return FALSE;
}

if ( LOBYTE( wsaData.wVersion ) != 2 ||
     HIBYTE( wsaData.wVersion ) != 0 )
{
    WSACleanup();
    return FALSE;
}

SOCKET client;

client = socket( AF_INET, SOCK_STREAM, 0 );

sockaddr_in sin;

memset( &sin, 0, sizeof sin );

sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr("127.0.0.1");
sin.sin_port = htons(5555);

if ( connect(client, (SOCKADDR*)(&sin), sizeof sin ) == SOCKET_ERROR ){
    return FALSE;
}

int int_data = 4;
    int bytes = send(client, (char*) &int_data, sizeof(int), 0);

}

4

3 回答 3

3

这是问题所在:

int bytes = recv(server, (char*) &int_data, sizeof(int), 0);

应该:

int bytes = recv(client, (char*) &int_data, sizeof(int), MSG_WAITALL);

其他一些挑剔的事情,不会导致您的问题,但您应该知道:

  1. 不要将您的服务器套接字绑定到 10.0.0.5。绑定到 0 (INADDR_ANY)。这样,当您在 IP 地址为 10.0.0.6 的机器上运行代码时,您的代码仍然可以工作。

  2. 使用 htonl()、htons()、ntohs() 和 ntohl() 与大端框进行互操作。

  3. 始终检查套接字调用的返回值。如果 recv 返回 0 或 -1,则表示远程端已断开连接。(从技术上讲,0 意味着客户端已停止发送,但除非您正在关闭半关闭的东西,否则这意味着他已断开连接)。

  4. TCP 套接字不是面向消息的,它们是面向流的。也就是说,仅仅因为您告诉 recv() 获取 N 个字节,并不意味着它将返回 N 个字节。IP 分段、TCP 分段和其他因素可以使 recv() 返回部分数据。根据需要使用 MSG_WAITALL 标志。

于 2012-06-02T20:47:11.377 回答
1

你自己让这几乎是不可能的。与其从代码开始,不如从协议规范开始。您可以查看使用 TCP 的现有协议(例如 HTTP、IMAP 等)的规范,以了解协议规范应包含哪些内容。

协议规范应该解释在字节级别发送或接收的所有内容。它应该解释连接是如何建立和拆除的。它应该解释如何从任一端检测到死连接。如果协议有应用层消息,它应该解释它们是如何分隔的以及接收者如何找到消息的结尾。它应该指定谁在何时传输。

然后,调试很容易。遵循此流程图:

1)服务器是否遵循规范?如果没有,服务器坏了。

2) 客户是否遵循规范?如果没有,则客户端已损坏。

3) 如果还是不行,说明规范有问题。

这样可以确保服务器和客户端一起工作。如果他们不这样做,就可以知道哪一侧需要修复。

制定一个协议规范只需要一两个小时,我向您保证,节省的时间将是非常值得的。只需要一次,当某件事不起作用时,您更改了错误的结尾(然后发现很多东西都是新损坏的,因为您修复了其中一个正确的地方)来支付所花费的时间。另外,作为奖励,可以进行其他实现。

于 2012-06-02T22:52:38.093 回答
0

我也被这个问题困住了,我注意到我的客户甚至没有连接。

尝试保存 connect() 和 recv() 返回的值,确保其 > -1 或打印出一些错误。

于 2013-07-06T02:23:55.867 回答