我如何通过套接字发送位字段?

时间:2011-05-24 21:21:32

标签: c sockets networking

我需要发送一组位字段以及从客户端到服务器的字符串。

所以我有:

#define YES 1
#define FLAG 2
int main(int argc, char* argv[])
{
    return sendToServer("The Message", YES | FLAG);
}
int sendToServer(char* msg, int bitfields)
{
   /* create socket and connect to server */
   /* Assume sock is set */
   send(sock, msg, strlen(msg), 0);
   return 0;
}

发送位域的最佳方法是什么?反正有没有将字段和字符串一起发送?

编辑:好的,我正在尝试实现Vlad的方法。我的客户与他所写的内容非常相似。我已将标志放在开始数据[0]并且我使用了htonl而不是bswap。我的服务器:

int main(int argc, char* argv[])
{
    /* create socket and wait for connection */
    char buffer[BUFFERSIZE];
    size_t rcvdB = recv(clntSock, buffer, sizeof(int),0);
    int flags = ntohl((int) buffer);
    rcvdB = recv(clntSock, buffer, sizeof(size_t),0);
    size_t msgSize = ntohl((size_t) buffer);
    rcvdB = recv(clntSock,buffer,msgSize,0);
    /* Then I send back to the client */
    ssize_t sntB = send(clntSock,buffer,msgSize,0);
}

当客户端打印消息时,消息末尾有多个ascii字符。

EDIT2:

当我读取超过8个字节的数据

时,似乎会发生这个问题

4 个答案:

答案 0 :(得分:2)

这当然取决于您的网络协议。如果您正在设计它,并且您最多要发送8个标志,请将它们放在消息的第一个字节中。如果你最多有16个,但它们在前两个字节中等等。

int sendToServer(int sock, char* msg, int flags)
{
    size_t siz = strlen(msg) + 1;  // +1 for NUL
    unsigned char *buf = malloc_or_die(siz + 1);
    buf[0] = flags;
    memcpy(buf + 1, msg, size);

    send(sock, msg, strlen(msg), 0);

    free(buf);
    return 0;
}

(我将bitfields更改为flags,因为它们就是这样。位域是标志的集合。)

答案 1 :(得分:2)

正如其他人所指出的,它取决于协议。我会用这样的东西:

int sendToServer(char* msg, int bitfields)
{
   unsigned int bits = bswap32 (bitfields); // Convert host to network byte order.

   size_t len = strlen (msg);   // Calculate string length.
   size_t nlen = bswap64 (len); // Convert length's byte order from host to network.

   iovec data[3]; // Prepare 3 I/O buffers to send data by performing a single system call (they are expensive).

   // Send length of the string first.
   data[0].iov_base = &nlen;
   data[0].iov_len = sizeof (nlen);

   // Send string...
   data[1].iov_base = msg;
   data[1].iov_len = len;

   // And, of course, send bits.
   data[2].iov_base = &bits;
   data[2].iov_len = sizeof (bits);

   // Write all of those to the socket.
   writev (fd, &data, sizeof (data) / sizeof (data[0]));
}

在接收方,您可以读取第一个sizeof (size_t)字节,从网络转换为主机字节顺序,转换为size_t。这将告诉你字符串的长度。然后读取那个长度的缓冲区 - 这将是你的字符串。最后,读取另一个sizeof (int)字节 - 这将是您的位域。

另见:

答案 2 :(得分:1)

最好将位域作为原始int(例如send(sock, &bitfields, sizeof(bitfields), 0))的字节发送,确保大小和位置相同。对于客户和客户而言,字节顺序是相同的。服务器。在字符串之前发送位可能是最容易的,因为服务器可以在固定的字节数之后轻松地提取字符串。

答案 3 :(得分:0)

位域形成一个数字,例如1|2%01 | %10 = %11开始给出3。

所以你要发送的就是那个号码。

snprintf(buffer, buffer_size, "%s-%d", message, number);
send(sockfd, buffer, buffer_size, 0);