在c中发送缓冲区长度和缓冲区

2 c sockets

我正在尝试使用C将字符串发送到服务器应用程序,但我遇到了麻烦.我对网络编程很新,我认为我的代码正在咆哮错误的树.

该消息应该是消息长度+消息,并且由python服务器在另一侧解压缩(buf是原始传入数据):

msg_len_bytes = buf[0:4]
msg_len = struct.unpack("!L", msg_len_bytes)[0]
Run Code Online (Sandbox Code Playgroud)

!表示网络字节顺序,L表示无符号长整数.

发送常规字符串相当简单.发送(袜子,消息,strlen(消息),0);

但是添加消息长度我无法理解.这是我的客户端到目前为止的代码:

struct msgstruct {
        uint32_t length;
        char send_data[4096];
};

int main()

{
    int sock;
    struct msgstruct message;
    char data[4096] = "<MOP><test/></MOP>";

    for ( int i = 0; i < strlen(data); i++ ) {
      message.send_data[i] = data[1];
    }

    struct hostent *host;
    struct sockaddr_in server_addr;

    unsigned long buflen = sizeof(message.send_data);
    uint32_t bufsend = htonl(buflen);

    message.length = bufsend;

    host = gethostbyname("127.0.0.1");

    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("Socket");
        exit(1);
    }

    server_addr.sin_family = AF_INET;     
    server_addr.sin_port = htons(12998);   
    server_addr.sin_addr = *((struct in_addr *)host->h_addr);
    bzero(&(server_addr.sin_zero),8); 


    if (connect(sock, (struct sockaddr *)&server_addr,
                sizeof(struct sockaddr)) == -1) {
        perror("Connect");
        exit(1);
    }

    if(send(sock, message.length + message.send_data, sizeof(message), 0) == -1){
        printf("\nSocket error.");
        exit(1);
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我尝试了一些变化,但我总是遇到套接字错误.是因为我在派遣的第二个争论中混合了类型吗?如果我尝试发送结构,我会收到编译错误.

abe*_*nky 5

错误在这段代码中:

send(sock, message.length + message.send_data, sizeof(message), 0)
Run Code Online (Sandbox Code Playgroud)

发送的原型是:

ssize_t send(int s, const void *buf, size_t len, int flags);
Run Code Online (Sandbox Code Playgroud)

请注意,参数 2 是一个指针。在您的代码中,您已将其作为长度(类型 uint32_t)添加到缓冲区(类型 char*)中。此添加将导致 char*, (pointer-to-char) 但指向不可预测且无意义的内存区域的指针。

要获得指向缓冲区的指针,您需要:

send(sock, &message, sizeof(message), 0)
Run Code Online (Sandbox Code Playgroud)

请注意,由于填充问题,获取结构的地址不是可移植的或总是可取的。但是在典型的 32 位架构上,这应该没问题。

这将发送从消息结构开始的数据,但发送 4100 (4096+4) 个字节!。我不认为你打算发送那么多。第三个参数表示要发送的字节数,应设置为:

sizeof(uint32_t) + strlen(data);  // 4-byte Integer + Length of the data "<MOP><test/></MOP>"
Run Code Online (Sandbox Code Playgroud)

请注意,这并没有包括空终止的数据,但是您最初的环没有抄一空,要么终结者

(如果你想要空终止符,让你的初始 for 循环转到strlen(data)+1,并在其他地方使用strlen(data)+1)。

理想情况下,您应该将 strlen(data) 缓存到局部变量中,而不是过多调用它。(您还在初始 for 循环中反复调用 strlen )。

您的最终声明将如下所示:

if(send(sock, &message, sizeof(uint32_t)+strlen(data), 0) == -1){
    printf("\nSocket error.");
    exit(1);
}
Run Code Online (Sandbox Code Playgroud)

试试看,让我知道它是怎么回事。


Mik*_*nov 5

您可以使用2个后续发送:

send(sock, &message.length, sizeof(message.length), 0);
send(sock, message.send_data, message.length*sizeof(char), 0);
Run Code Online (Sandbox Code Playgroud)

或者更好地准备前4个字节的缓冲区作为消息长度:

char buff[MAX_BUFF] = "";
int  len_disp = sizeof(message.length);
memcpy(buff, &message.length, len_disp);
memcpy(&buff[len_disp], &message.length, message.length*sizeof(char));
send(sock, buff, message.length*sizeof(char) + len_disp, 0);
Run Code Online (Sandbox Code Playgroud)

编辑:对于小消息评论 - 禁用Nagle的算法.

BOOL bNagleEnabled = FALSE;
if(setsockopt(sAccept, IPPROTO_TCP, TCP_NODELAY, (char *)&bNagleEnabled, sizeof(BOOL)))
{
  ReportError("Setting TCP_NODELAY socket option failed");
  return -2;
}
Run Code Online (Sandbox Code Playgroud)