Linux/Unix网络编程指南(Socket 编程)—(9)
作者:转载自:更新时间:2009-8-2

send() and recv()--Talk to me, baby!
这两个函数用于流式套接口和数据报套接口的通讯。如果你喜欢使用无连接的数据报 套接口,你应该看一看下面关于 sendto() 和 recvfrom() 的章节。
send() 是这样的:
  int send(int sockfd, const void *msg, int len, int flags);
sockfd 是你想发送数据的套接口描述符(或者是调用 socket() 或者是 accept() 返回的。)msg 是指向你想发送的数据的指针。len 是数据的长度。把 flags 设置为 0 就可以了。(详细的资料请看 send() 的 man page)。
这里是一些可能的例子:
  char *msg = "Beej was here!";
  int len, bytes_sent;
  .
  .
  len = strlen(msg);
  bytes_sent = send(sockfd, msg, len, 0);
 .
.
  .
send() 返回实际发送的数据的字节数--他可能小于你要求发送的数目!也即你告诉他要发送一堆数据可是他不能处理成功。他只是发送他可能发送的数据,然后希望你以后能够发送其他的数据。记住,如果 send() 返回的数据和 len 不匹配,你应该发送其他的数据。但是这里也有个好消息:如果你要发送的包很小(小于大约 1K),他可能处理让数据一次发送完。最后,在错误的时候返回-1,并设置 errno。
recv() 函数很相似:
  int recv(int sockfd, void *buf, int len, unsigned int flags);
sockfd 是要读的套接口描述符。buf 是要读的信息的缓冲。len 是 缓冲的最大长度。flags 也可以设置为0。(请参考recv() 的 man page。)
recv() 返回实际读入缓冲的数据的字节数。或者在错误的时候返回-1,同时设置 errno。
很简单,不是吗? 你现在可以在流式套接口上发送数据和接收数据了。你现在是 Unix 网络程序员了!
--------------------------------------------------------------------------------
sendto() 和 recvfrom()--Talk to me, DGRAM-style
"这很不错啊",我听到你说,"但是你还没有讲无连接数据报套接口呢。"没问题,现在我们开始 这个内容。
既然数据报套接口不是连接到远程主机的,那么在我们发送一个包之前需要什么信息呢? 不错,是目标地址!看下面的:
  int sendto(int sockfd, const void *msg, int len, unsigned int flags,
     const struct sockaddr *to, int tolen);
你已经看到了,除了另外的两个信息外,其余的和函数 send() 是一样的。 to 是个指向数据结构 struct sockaddr 的指针,他包含了目的地的 IP 地址和断口信息。tolen 可以简单地设置为 sizeof(struct sockaddr)。
和函数 send() 类似,sendto() 返回实际发送的字节数(他也可能小于你 想要发送的字节数!),或者在错误的时候返回 -1。
相似的还有函数 recv() 和 recvfrom()。recvfrom() 的定义是 这样的:
  int recvfrom(int sockfd, void *buf, int len, unsigned int flags
        struct sockaddr *from, int *fromlen);
又一次,除了一点多余的参数外,这个函数和 recv() 也是一样的。from 是 一个指向局部数据结构 struct sockaddr 的指针,他的内容是源机器 的 IP 地址和端口信息。fromlen 是个 int 型的局部指针,他的初始值 为 sizeof(struct sockaddr)。函数调用后,fromlen 保存着 实际储存在 from 中的地址的长度。
recvfrom() 返回收到的字节长度,或者在发生错误后返回 -1。
记住,如果你是用 connect() 连接一个数据报套接口,你可以简单的调用 send() 和 recv() 来满足你的要求。这个时候依然是数据报套接口,依然使用 UDP,系统 自动的加上了目标和源的信息。