【UNIX网络编程(二)】基本TCP套接字编程函数

基于TCP客户/server程序的套接字函数图例如如下:网络


运行网络I/O。一个进程必须作的第一件事就是调用socket函数。指按期望的通讯协议类型。socket

#include <sys/socket.h>函数

int socket(int family, int type, int protocol);/*返回值:若成功则为非负描写叙述符,若出错则为-1*/spa

socket函数成功时返回一个小的非负整数值,它与文件描写叙述符相似。把它称为套接字描写叙述符,简称sockfd。family參数指明协议族。被称为协议域。type參数指明套接字类型。指针

protocol參数应该是某个协议类型常值。或者为0,以选择所给定family和type组合的系统默认值。server

各參数列于一下表格:接口

family 说明 type 说明 protocol 说明
AF_INET IPv4协议 SOCKET_STREAM 字节流套接字 IPPROTO_TCP TCP传输协议
AF_INET6
IPv6协议 SOCK_DGRAM 数据报套接字 IPPROTO_UDP UDP传输协议
AF_LOCAL Unix域协议 SOCK_SEQPACKET 有序分组套接字 IPPROTO_SCTP SCTP传输协议
AF_ROUTE 路由套接字 SOCK_RAM 原始套接字

AF_KEY 秘钥套接字




TCP客户用connect函数来创建与TCPserver的连接。生命周期

#include <sys/socket.h>队列

int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);  /*返回:若成功则为0。若出错则为-1*/进程

sockfd是由socket函数返回的套接字描写叙述符。第二个、第三个參数各自是一个指向套接字地址结构的指针和该结构的大小。客户在调用函数connect前没必要非得调用bind函数,因为假设需要的话,内核会肯定源IP地址,并选择一个暂时port号做为源port。假设是TCP套接字,调用connect函数将激发TCP的三路握手过程,而且仅在链接创建成功或出错时才返回,当中出错返回可能有下面几种状况:

a、若TCP客户没有收到SYN分节的响应,则返回ETIMEDOUT错误。

b、若对客户的SYN的响应是RST(表示复位),则代表该server主机在咱们指定的port上没有进程在等待与之链接。

c、若客户发出的SYN在中间的某个路由器上引起了一个“destination unreachable”ICMP错误。则以为是一个软错误。


bind函数把一个本地协议地址赋予一个套接字。对于网际网协议,协议地址是32位的IPv4地址与16位的TCP或UDPport号的组合。


#include <sys/socket.h>

int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);/*返回,成功则为0,出错则为-1*/

第二个參数是一个指向特定于协议的地址结构的指针。第三个參数是该地址结构的长度,对于TCP。调用bind函数可以指定一个port号。或指定一个IP地址,也可以二者都指定。还可以都不指定。

server在启动时捆绑它们的众所周知port。假设一个TCP客户或server不曾调用bind捆绑一个port,当调用connect或listen时。内核就要为对应的套接字选择一个暂时port号。让内核选择暂时port对于TCP客户来讲是正常的。除非应用需要一个预留port;而毁于TCPserver来讲却极为罕见,因为server是经过他们的众所周知port被你们认识的。

进程可以把一个特定的IP地址捆绑到它的套接字上,只是这个IP地址必须属于其所在主机的网络接口之中的一个。

假设指定port号为0,那么内核就bind被调用时选择一个暂时port。然而假设指定IP地址为通配地址。那么内核将等到套接字已链接TCP或已在套接字上发出数据报时才选择一个IP地址。对于IPv4来讲,通配地址由常量INADDR_ANY来指定,其值为0。

注意:假设让内核来为套接字选择一个暂时port号,那么必须注意。函数bind并不返回所选择的值。实际上。由于bind函数的第二个參数有const限定词,它没法返回所选之值。

为了获得内核所选择的这个暂时port值,必须调用函数getsockanme来返回协议地址。


listen函数仅由TCPserver调用,它作两件事:

一、当socket函数建立一个套接字时,它被若是为一个主动套接字,也就是说。它是一个将调用connect发起链接的客户套接字。listen函数把一个未链接的套接字转换成一个被动套接字,指示内核应该受指向该套接字的链接请求。

二、本函数的第二个參数规定了内核应该为对应套接字排队的最大链接个数。

#include <sys/socket.h>

int listen(int sockfd, int backlog);/*返回:若成功则为0。出错则为-1*/

本函数一般应该在调用socket和bind这两个函数以后。并在调用accept函数以前调用。

为理解backlog參数。必须认识到内核为不论什么一个给定的监听套接字维护两个队列:

一、未完毕链接队列。每个这种SYN分节相应当中一项:已由某个客户发出并到达server,而server正在等待完毕相应的TCP三路握手过程,这些套接字处于SYN_RCVD状态

二、已完毕链接队列,每个已完毕TCP三路握手过程的客户相应当中一项。这些套接字处于ESTBLISHED状态。


accept函数由TCPserver调用,用于从已完毕链接队列返回下一个已完毕链接。假设已完毕链接队列为空,那么进程被投入睡眠。

#include <sys/socket.h>

int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);   /*返回:若成功则为负描写叙述符。若出错则为-1*/

參数cliaddr和addrlen用来返回已链接的对端进程协议地址。假设accept成功,那么其返回值是由内核本身主动生成的一个全新描写叙述符,表明与所返回客户的TCP连接。在讨论accept函数时,称第一个參数为监听套接字描写叙述符。称返回值为已链接套接字描写叙述符。区分这两个套接字很重要。

一个server一般只建立一个监听套接字,它在该server的生命周期内一直存在。

内核为每个由server进程接受的客户链接建立一个已链接套接字。当server完毕对某个给定客户的服务时,对应的一两节套接字就被关闭。

本函数最多返回3个值:一个既多是新套接字描写叙述符也多是出错仅仅是的整数、客户进程的协议地址以及该地址的大小。假设对返回客户协议地址不感兴趣,可以把cliaddr和addrlen均置为空指针。


close函数用来关闭套接字。并终止TCP链接。int close(int sockfd)。返回:成功则为0。出错则为-1。