《UNIX环境高级编程》-socket根本函数的解析

《UNIX环境高级编程》--socket基本函数的解析





#include <sys/socket.h>

int socket (int family, int type, int protocol);

Returns: non-negative descriptor if OK, -1 on error



说明:
1. family 参数通常取值 AF_INET 或 AF_INET
2. type 参数通常取值有 SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET, SOCK_RAW




#include <sys/socket.h>

int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);

Returns: 0 if OK, -1 on error



说明:
1. 关于 connect 的返回值:
1)如果客户端 SYN 报文段没有收到任何响应,返回 ETIMEDOUT
2)如果服务端对客户端 SYN 的响应是 RST ,返回 ECONNREFUSED
3)如果客户端 SYN 引发 ICMP "destination unreachable" ,重发无效的情况下,返回 EHOSTUNREACHENETUNREACH (ICMP "destination unreachable" 反映网络暂时情况,所以应重发)
4)关于 connect 返回值详细请参看




#include <sys/socket.h>

int bind (int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);

Returns: 0 if OK,-1 on error

 

 

#include <sys/socket.h>

#int listen (int sockfd, int backlog);

Returns: 0 if OK, -1 on error


说明:
1. 关于 backlog 参数
1)可以排队等待的连接数(包括未完成的和已完成的)。内核提供的连接相关的2个队列如下所示:


2)由于实现的不同,不要指定 backlog 为 0 。不想监听,直接关闭 socket 即可。
3)当队列满时,对于客户端到来的 SYN ,一般会忽略,而不发送 RST。原因是队列满是暂时情况,当客户端再次重发 SYN 时,也许就可以接收了。而如果向客户端回复 RST ,则客户端 connect 函数会返回错误。这样客户程序必须去处理,而不是 TCP 重传机制。另外,对于服务端发过来的 RST ,客户端并不能区分是由于 “没有服务进程监听该端口”, 还是由于 “该端口队列已满” 。
4)当连接三次握手完成之后、accept 接收之前,也就是处在已完成队列时,客户端发来的数据会被服务端 TCP 排队保存起来,直到 socket 的接受缓冲区大小为止。




#include <sys/socket.h>

int accept (int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);

Returns: non-negative descriptor if OK, -1 on error





#include <unistd.h>

pid_t fork(void);

Returns: 0 in child, process ID of child in parent, -1 on error





#include <unistd.h>

int execl (const char *pathname, const char *arg0, ... /* (char *) 0 */ );

int execv (const char *pathname, char *const argv[]);

int execle (const char *pathname, const char *arg0, ...

/* (char *) 0, char *const envp[] */ );

int execve (const char *pathname, char *const argv[], char *const envp[]);

int execlp (const char *filename, const char *arg0, ... /* (char *) 0 */ );

int execvp (const char *filename, char *const argv[]);

All six return: -1 on error, no return on success


说明:
1. 六个函数的区别是
1)是路径名还是文件名?
2)传给新程序的参数是挨个传递还是通过指针数组 argv ?
3)是继承调用进程的环境变量还是传递新的环境变量?
2. 参数 arg0 等同于 main 函数中的 argv[0],表示程序名。最后的空指针 (char *) 0 表明参数列表的结束。



#include <unistd.h>

int close (int sockfd);

Returns: 0 if OK, -1 on error




#include <sys/socket.h>

int shutdown(int sockfd, int howto);

Returns: 0 if OK, –1 on error


说明:
1. close 减少描述字的引用计数,当引用计数为 0 时,close 函数关闭该 socket 。另外,close 终止读、写两个方向的数据传输。
2. shutdown 函数忽略引用计数,并不关闭 socket (也就是说不释放描述字资源),只是断开连接。howto 参数指明如何断开连接,有 3 种取值:
1)SHUT_RD     关闭套接字的读功能,也就是说不能再从该 socket 读数据。读缓冲区中现有的数据被丢弃,后续该 socket 接收到数据也全部被丢弃。具体实现中,能认为shutdown (fd, SHUT_RD)是空操作,因为shutdown后还能继续从该socket读取数据,这点也许还需要进一步证实。
2)SHUT_WR     关闭套接字的写功能,也就是说不能再向该 socket 写数据,对应于 TCP连接的半关闭。写缓冲区中的数据会被写出,随后启动TCP连接正常的终止序列。当发送 FIN 之后,如果对该 socket 调用 write 操作,则会引发 SIGPIPE/EPIPE 。
3)SHUT_RDWR      读写功能全部关闭。相当于先用 SHUT_RD 调用 shutdown ,再用 SHUT_WR 调用 shutdown 。




#include <sys/socket.h>

int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);

int setsockopt(int sockfd, int level, int optname, const void *optval socklen_t optlen);

Both return: 0 if OK,–1 on error


说明:
1. level 参数指定套接字选项的等级,通常为 SOL_SOCKET .。
2. 最后一个参数是获取或者设定的套接字的值的长度。
3. 套接字选项通常分为两类:
1)二进制选项(flag)。通常用来开启或关闭某一项功能。
2)特定值选项(value)。通常可以设置或者检测的某个选项的特定值。
4. 某些选项需要注意设置的时间,必须在 listen 之前对监听的套接字设定,然后继承给连接套接字,否则起不到作用。比如 SO_REUSEADDR、SO_LINGER、SO_RCVBUF、SO_SNDBUF 等。

※ 关于套接字的详细说明,请参看



#include <sys/socket.h>

ssize_t recv(int sockfd, void *buff, size_t nbytes, int flags);

ssize_t send(int sockfd, const void *buff, size_t nbytes, int flags);

Both return: number of bytes read or written if OK, –1 on error


说明:
1. 需要设定时,flags 参数可以取以下值;不需要时,设为 0 。


各选项详细解释如下:

MSG_DONTROUTE

This flag tells the kernel that the destination is on a locally attached network and not to perform a lookup of the routing table. We provided additional information on this feature with the SO_DONTROUTE socket option (). This feature can be enabled for a single output operation with the MSG_DONTROUTE flag, or enabled for all output operations for a given socket using the socket option.

MSG_DONTWAIT

....................................................................


This flag is newer than the others and might not be supported on all systems.

MSG_OOB

With send, this flag specifies that out-of-band data is being sent. With TCP, only one byte should be sent as out-of-band data, as we will describe in . With recv, this flag specifies that out-of-band data is to be read instead of normal data.

MSG_PEEK

This flag lets us look at the data that is available to be read, without having the system discard the data after the recv or recvfrom returns. We will talk more about this in .

MSG_WAITALL

This flag was introduced with 4.3BSD Reno. It tells the kernel not to return from a readreadn function () and replace it with the following macro: operation until the requested number of bytes have been read. If the system supports this flag, we can then omit the

#define readn(fd, ptr, n) recv(fd, ptr, n, MSG_WAITALL)

Even if we specify MSG_WAITALL, the function can still return fewer than the requested number of bytes if (i) a signal is caught, (ii) the connection is terminated, or (iii) an error is pending for the socket.


※ 通常用 MSG_DONTWAIT | MSG_PEEK 来检查 socket 上有多少数据可读。需要注意的是,对于 TCP socket ,连续两次调用 recv 的返回值可能有所不同,原因是两次调用的间隔可能有新数据到来。而对于 UDP socket ,如果接受队列中有一个数据报的话,则前后两次 recv 的返回值是完全相同的。




#include <sys/uio.h>

ssize_t readv(int filedes, const struct iovec *iov, int iovcnt);

ssize_t writev(int filedes, const struct iovec *iov, int iovcnt);

Both return: number of bytes read or written, –1 on error


说明:
1. readv 被称为 散布读 ,即将文件中若干连续的数据块读到分散的缓存区中;writev 被称为 聚集写,即将分散的缓存区中的数据连续写至文件。
2.
struct iovec {
void *iov_base; /* starting address of buffer */
size_t iov_len; /* size of buffer */
};该结构为 POSIX 定义,有的实现 iov_base 定义为 char * ,iov_len 定义为 int 。
3. iovec 数组元素个数通常有限制,POSIX 要求定义 IOV_MAX (通常为 16) 。



#include <sys/socket.h>

ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

ssize_t sendmsg(int sockfd, struct msghdr *msg, int flags);

Both return: number of bytes read or written if OK, –1 on error


说明:
1. 这两个为最通用的读写函数,能够代替之前所介绍的读写函数。
2.
struct msghdr {
void *msg_name; /* protocol address */
socklen_t msg_namelen; /* size of protocol address */
struct iovec *msg_iov; /* scatter/gather array */
int msg_iovlen; /* # elements in msg_iov */
void *msg_control; /* ancillary data (cmsghdr struct) */
socklen_t msg_controllen; /* length of ancillary data */
int msg_flags; /* flags returned by recvmsg() */
};
当用于非连接的 socket 时(比如,非连接的 udp),msg_name 和 msg_namelen 相当于 recvfrom 的第五和第六个参数,指明 socket 地址结构及其长度。msg_namelen 对于 sendmsg 是输入参数,而对 recvmsg 则是输入输出参数。
msg_iov 和 msg_iovlen 与 readv 的第二和第三个参数相似。
msg_control 和 msg_controllen 表示可选的 ancillary data 的地址及其大小。msg_controllen 对于 recvmsg 同样是输入输出参数。关于 ancillary data ,请参看 。
msg_flags 仅用于 recvmsg ,sendmsg 时设置该值无效。调用 recvmsg 时,参数 flags 的值被拷贝到 msg_flags ,内核利用其驱动接收处理,结束后根据处理结构更新该值。

下表列举了用于输入输出的各种标志


前4个用于内核检查,中间2个既可以检查也可以返回,最后的只用于内核返回。

MSG_BCAST

This flag is relatively new, supported by at least BSD, and is returned if the datagram was received as a link-layer broadcast or with a destination IP address that is a broadcast address. This flag is a better way of determining if a UDP datagram was sent to a broadcast address, compared to the IP_RECVDSTADDR socket option.

MSG_MCAST

This flag is also a fairly recent addition, supported by at least BSD, and is returned if the datagram was received as a link-layer multicast.

MSG_TRUNC

This flag is returned if the datagram was truncated; in other words, the kernel has more data to return than the process has allocated room for (the sum of all the iov_len members). We will discuss this more in .

MSG_CTRUNC

This flag is returned if the ancillary data was truncated; in other words, the kernel has more ancillary data to return than the process has allocated room for (msg_controllen).

MSG_EOR

This flag is cleared if the returned data does not end a logical record; the flag is turned on if the returned data ends a logical record. TCP does not use this flag since it is a byte-stream protocol.

MSG_OOB

This flag is never returned for TCP out-of-band data. This flag is returned by other protocol suites (e.g., the OSI protocols).

MSG_NOTIFICATON

This flag is returned for SCTP receivers to indicate that the message read is an event notification, not a data message.


3. 下表是各种输入输出函数的比较







#include <sys/socket.h>

int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen);

int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen);

Both return: 0 if OK, -1 on error


说明:
1. 这两个函数的应用场景
1)由于客户端没有绑定,connect 成功后,调用 getsockname 获取本地IP地址和端口号。
2)当服务端以端口号为 0 值调用bind 时,使用 getsockname 获取内核分配的本地端口号。
3)当服务端以通配符IP地址调用 bind 时,使用 getsockname 获取内核分配的本地IP地址。
4)当调用 exec 系列函数后,只能通过 getpeername 获取对等端的信息。

详细请点击:http://www.verydemo.com/demo_c170_i15420.html