在套接字进行通信时,首先要建立服务器进程和客户端进程之间的连接,连接创建成功之后才可以传输数据,以下是套接字通信的过程:
调用函数 socket 创建套接字描述符时,该套接字描述符是存储在它的协议族空间中,没有具体的地址,要使它有一个地址,可以调用函数 bind 使其与地址绑定。客户端的套接字关联的地址可有系统默认分配,因此不需要指定具体的地址。若要为服务器端套接字绑定地址,可以通过调用函数 bind 将套接字绑定到一个地址。
/* 套接字的基本操作 */ /* * 函数功能:将地址绑定到一个套接字; * 返回值:若成功则返回0,若出错则返回-1; * 函数原型: */ #include <sys/socket.h> int bind(int sockfd, const struct sockaddr *addr, socklen_t len); /* * 说明: * sockfd 为套接字描述符; * addr是一个指向特定协议地址结构的指针; * len是地址结构的长度; */
bind 函数的调用不是必须的,可以在创建套接字描述符之后调用 connect 或 listen 函数,这时内核系统会自动给该套接字分配一个地址和端口。只有在希望进程使用某个特定的网络地址和端口时,才是使用 bind 函数。
为了获取已绑定到套接字的地址,我们可以调用函数 getsockname 来实现:
/* * 函数功能:获取已绑定到一个套接字的地址; * 返回值:若成功则返回0,若出错则返回-1; * 函数原型: */ #include <sys/socket.h> int getsockname(int sockfd, struct sockaddr *addr, socklen_t *alenp); /* * 说明: * 调用该函数之前,设置alenp为一个指向整数的指针,该整数指定缓冲区sockaddr的大小; * 返回时,该整数会被设置成返回地址的大小,如果该地址和提供的缓冲区长度不匹配,则将其截断而不报错; */ /* * 函数功能:获取套接字对方连接的地址; * 返回值:若成功则返回0,若出错则返回-1; * 函数原型: */ #include <sys/socket.h> int getpeername(int sockfd, struct sockaddr *addr, socklen_t *alenp); /* * 说明: * 该函数除了返回对方的地址之外,其他功能和getsockname一样; */
在处理面向连接的网络服务时,交换数据之前必须在请求的进程套接字和提供服务的进程套接字之间建立连接。可以调用函数 connect 建立一个连接:
/* * 函数功能:建立连接; * 返回值:若成功则返回0,出错则返回-1; * 函数原型: */ #include <sys/socket.h> int connect(int sockfd, const struct sockaddr *addr, socklen_t len); /* * 说明: * sockfd是系统调用的套接字描述符; * addr是目的套接字的地址,即想与之通信的服务器地址; * len是目的套接字的大小; * * 如果sockfd没有绑定到一个地址,connect会给调用者绑定一个默认地址; */在编写服务器程序时需要使用监听函数 listen 。服务器进程不知道要与谁连接,因此,它不会主动地要求与某个进程连接,只是一直监听是否有其他客户进程与之连接,然后响应该连接请求,并对它做出处理,一个服务进程可以同时处理多个客户进程的连接。一般函数 listen 与函数 accept 一起使用,先使用监听函数 listen,然后使用 accept 逐一处理各个连接,其定义如下:
/* * 函数功能:接收连接请求; * 函数原型: */ #include <sys/socket.h> int listen(int sockfd, int backlog);//若成功则返回0,若出错则返回-1; /* * sockfd是套接字描述符; * backlog是该进程所要入队请求的最大请求数量; */ int accept(int sockfd, struct sockaddr *addr, socklen_t *len);//返回值:若成功返回套接字描述符,出错返回-1; /* * 说明: * 该函数返回套接字描述符,该描述符连接到调用connect函数的客户端; * 这个新的套接字描述符和原始的套接字描述符sockfd具有相同的套接字类型和地址族,而传给accept函数的套接字描述符sockfd没有关联到这个链接, * 而是继续保持可用状态并接受其他连接请求; * 若不关心客户端协议地址,可将addr和len参数设置为NULL,否则,在调用accept之前,应将参数addr设为足够大的缓冲区来存放地址, * 并且将len设为指向代表这个缓冲区大小的整数指针; * accept函数返回时,会在缓冲区填充客户端的地址并更新len所指向的整数为该地址的实际大小; * * 若没有连接请求等待处理,accept会阻塞直到一个请求到来; */
《UNIX高级环境编程》