簡體   English   中英

C套接字發送/ recv緩沖區類型

[英]C sockets send/recv buffer type

我正在使用unix套接字,當我的緩沖區是char類型(即發送和接收字符串)時,我可以發送()和recv()數據。 我使用了Beej的套接字指南,所用的例子是發送/接收字符串。

現在我想在一條消息中發送/ recv不同類型的數據。
例如,在一條消息中,我想發送一個整數,一個字符串,一個double和一個float。 我該怎么做呢? 更具體地說,我的消息“緩沖區”應該是什么類型的?

send和recv的原型:

int recv (int socket, void *buffer, size_t size, int flags)
int send (int socket, void *buffer, size_t size, int flags)

我對C / C ++和指針沒有太多經驗,所以這可能是一個noob問題。

如果有人能指導我朝着正確的方向前進,我真的很感激。 謝謝

最好的方法是封裝您想要在結構中傳遞的信息。 然后傳遞結構的地址和長度。 請注意, buffer是一個void*因此這允許您傳遞包含您的信息的結構的地址。

這是我用於工具安全副本的struct一小部分,

struct message
{
     size_t total_len;
     size_t filename_len;
     char *filename;
     size_t text_len;
     char *text;
     char *iv;
     char *salt;
     unsigned char *hmac;
};

然后在send_message()序列化message ,然后write socket

bool send_message(const struct message *msg, const char *ip, const char *port)
{
    ...
   connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
   // Serialize to file
   serialize(msg, "temp");

   // Transfer the file over the network
   fp = fopen("temp", "rb");
   while((n = fread(buffer, 1, MAX_BUF_LEN, fp)) != 0)
   {
       write(sockfd, buffer, n);
   }

   fclose(fp);
   remove("temp");

   close(sockfd);
}

正如@vitaut所建議的那樣,您可以使用庫進行serialize ,我已將其作為學習體驗實現。

您需要序列化發送方的對象並在接收方反序列化 在C ++中有許多庫,例如Boost Serialization,或者如果你想重新發明輪子,你可以隨時自己動手。

除非您計划發送大量數據(許多千字節)並經常(每秒幾個數據包),否則我建議您將數據轉換為字符串(也稱為“序列化數據”)並以此方式傳遞。 它有幾個好處:

  1. 它是可移植的 - 無論intfloatdouble大小是什么 - 或者字段之間的填充是什么。
  2. 它很容易調試(您只需查看數據並說明它是對還是錯)
  3. 發送/接收機器的字節順序無關緊要。

另一方面,發送二進制數據很復雜,因為您需要擔心數據字段的各個大小及其內部表示(字節順序,如何在二進制中重新表示double ,結構中數據字段的填充,不能通過指針等等)。 唯一的好處是二進制數據更緊湊。 但這只會影響你是否有很多千字節和/或每秒發送大量數據包。

那么,要回答問題(“我如何發送結構?”),你只需發送一個指向結構的指針。

struct foo
{
  int a;
  int b;
};

struct foo s;
s.a = 10;
s.b = 20;
send(socket,&s,sizeof(s),0);

它真的很容易。 現在,另一方必須是相同的(也就是說,系統A內存中的結構必須與系統B上的結構相匹配)。 更好的方法是使用更具體的類型和一些函數來正確排序數據:

#ifndef __GNUC__
#  define __attribute__(x)
#endif

#ifdef __SunOS
#  pragma pack(1)
#endif

struct foo
{
  uint32_t a;
  uint32_t b;
} __attribute__((packed));

#ifdef __SunOS
#  pragma pack()
#endif

struct foo s

/* to send */

s.a = htonl(10);
s.b = htonl(20);
send(socket,&s,sizeof(s),0);

/* to receive */
recv(socket,&s,sizeof(s),0);
s.a = ntohl(s.a);
s.b = ntohl(s.b);

當你想“通過網絡”“移植”發送二進制數據時,你可以看到它開始變得系統特定,這就是為什么人們要轉換為文本,或者很可能使用已經編寫的序列化庫。

這取決於這必須是多么便攜。

最簡單的方法是將所有內容轉換為ASCII,用逗號或分號分隔,然后在接收方再次解析它。

您還可以將其轉換為網絡字節順序並將其作為二進制發送。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM