connect()
客户端就是用connect()函数来建立与服务器之间的连接的。
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, struct sockaddr *serv_addr, int;
sockfd是我们的老朋友了,是由socket()函数返回的套接字描述符,serv_addr是一个执行套接字地址结构 struct sockaddr 的指针, struct sockaddr 中存储了目标IP地址和端口号信息,addrlen是serv_addr指向的struct sockaddr 大小。
再次强调一下 getaddrinfo() 的妙处,所有你需要的连接信息都可以从这个函数的返回结果中获取。
客户端在调用connect()之前不必非得调用bind()函数,因为如果有必要,内核会确定源IP地址,并选择一个临时端口号作为源端口。
举一个使用connect()连接到"www.chanmufeng.com" 的3490端口的例子:
struct addrinfo hints, *res;
int sockfd;
// first, load up address structs with getaddrinfo():
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
getaddrinfo("www.example.com", "3490", &hints, &res);
// make a socket:
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
// connect!
和上一节讲的bind()一样,有些老代码在调用connect()之前会手动封装 struct sockaddr_in,然后传给connect()作为参数。你现在仍然可以这么做,但是没必要!
如果你使用的是TCP套接字,调用connect函数会触发TCP的三次握手过程,而且仅在连接成功或者失败时才会返回,失败返回-1,并且会设置全局变量errno的值。
listen()
之前讲的函数服务端和客户端都可以使用,让我们换换口味,这次讲一个仅用于服务端的函数,不仅如此,它还只能用于TCP服务端。
身为服务端,肯定是需要等待随时可能到来的客户端连接,并采用某种方式处理连接。整个过程可以分为两步:先调用listen(),然后调用accept()(这是下一小节的内容)。
listen的调用非常简单,如下:
#include <sys/sock.h>
int listen(int sockfd, int;
虽然只有两个参数,但是其中有一些细节值得玩味。
sockfd就是通过socket()返回的一个普通socket file descriptor而已,系统默认这个socket只是一个等待进行主动连接的客户端socket。而listen函数会把这个客户端socket转换为服务端socket,告诉内核需要接受指向该socket的连接请求,并且该socket的TCP状态从CLOSED转换为LISTEN。
backlog参数表示内核应该为该套接字排队的最大连接个数。这是啥意思?所有客户端与该socket建立的连接都会在一个队列中排队等待,直到你accept()(见下节)它们,这个参数就表示最多有多少个连接有资格排队。大多数系统将这个值预设为20,你可以初始化为5或者10。
还有老生常谈的,listen() 在错误的时候会返回 -1,并设置 errno。
联系之前讲过的3个系统调用,创建服务端代码需要调用的函数依次为:
getaddrinfo();
socket();
bind();
listen();
/* accept() 将被写在这里 */
我只是列出了函数的调用顺序而已,这几个步骤都比较简单,稍微需要点处理技巧的是下一节的accept()。










