TCP网络编程总结
1.TCP交互流程
1.服务器根据地址类型(ipv4, ipv6)、socket类型、协议创建socket。
2.服务器为socket绑定IP地址和端口号。
3.服务器socket 监听端口号请求,随时准备接收客户端发来的连接,这时候服务器的socket并没有被打开。
4.客户端创建socket。
5.客户端打开socket,根据服务器IP地址和端口号试图连接服务器socket。
6.服务器socket接收到客户端socket请求,被动打开,开始接收客户端请求,直到客户端返回连接信息。这时候socket进入阻塞状态,所谓阻塞即accept()方法一直到客户端返回连接信息后才返回,开始接收下一个客户端谅解请求。
7.客户端连接成功,向服务器发送连接状态信息。
8.服务器accept方法返回,连接成功。
9.客户端向socket 写入信息。
10.服务器读取信息。
11.客户端关闭。
12.服务器端关闭。
2.TCP网络编程API
1.socket函数
int socket(int domain ,int type , int protocol) ;
1.domain :即协议域,又称为协议族(family) 。常用的协议族有: AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX, Unix域socket )、AF_ROUTE等。
2.type :指定socket类型。常用的socket类型有: SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等。其中, SOCK_STREAM表示提供面向连接的稳定数据传输,即TCP协议。SOCK_DGRAM 表示使用不连续、不可靠的数据包连接。
3.protocol :指定协议。常用的协议有, IPPROTO_TCP , IPPTOTO_UDP , IPPROTO_SCTP 、IPPROTO_TIPC 等,它们分别对应TCP 传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。
socket()用于创建一个socket描述符(socket descriptor),它唯一标识一个socket 。这个socket描述字和文件描述字一样,后续的操作都有用到它,把它作为参数,通过它来进行一些读写操作。
当调用socket创建一个socket时,返回的socket描述字它存在于协议族(addressfamily, AF_XXX )空间中,但没有一个具体的地址。
套接字描述符是一个整数类型的值。每个进程的进程空间里都有一个套接字描述符表,该表中存放着套接字描述符和套接字数据结构的对应关系。
根据套接字描述符就可以找到其对应的套接字数据结构。套接字数据结构都存放在操作系统的内核缓冲里。
一个套接字由相关五元组构成:协议、本地地址、本地端口、远程地址、远程端口。
2.bind函数
int bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen) ;
1.sockfd :即socket描述字,它是通过socket()函数创建来唯一标识一个socket的。bind()函数就是将给这个描述字绑定一个名字。
2.addr : 一个const struct sockaddr*指针,指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket时的地址协议族的不同而不同。
3.addrlen :对应的是地址的长度。
bind()函数把一个地址族中的特定地址赋给socket。
通常服务器端在调用listen之前会调用bind();而客户端就不用调用,而是在connect()时由系统随机生成一个。
返回值:如果函数执行成功,返回值为0 , 反之为SOCKET_ERROR。
3.listen函数
int listen(int sockfd , int backlog) ;
listen函数的第一个参数即为要监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数。
socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型,等待客户的连接请求。
4.connect函数
int connect(int sockfd , const struct sockaddr *addr, socklen_ t addrlen) ;
connect函数的第一个参数即为客户端的socket描述字,第二参数为服务器的socket地址,第三个参数为socket地址的长度。
客户端通过调用connect 函数来建立与TCP服务器的连接。
5.accept函数
int accept(int sockfd, struct sockaddr *addr, socklen_t addrlen) ;
accept函数的第一个参数为服务器的socket描述字; 第二个参数为指向struct sockaddr的指针,用于返回客户端的协议地址;第三个参数为协议地址的长度。
如果accpet成功,那么其返回值是由内核自动生成的一个全新的描述字,代表与返回客户的TCP连接。
accept的第一个参数为服务器的socket描述字,是服务器开始调用socket()函数生成的,称为监听socket描述字;而accept函数返回的是己连接的socket描述字。
一个服务器通常仅仅只创建一个监听socket描述字,它在该服务器的生命周期内一直存在。内核为每个由服务器进程接受的客户创建了一个已连接socket描述字,当服务器完成了对某个客户的服务,相应的巳连接socket描述字就被关闭。
6.read和write函数
read()/write()
recv()/send()
readv()/writev()
recvmsg()/sendmsg()
recvfrom()/sendto()
最常用的是read()和write():
read()的函数原型是:
ssize_t read(int fd, void *buf, size_t count);
1.socket 描述字fd;
2.缓冲区buf;
3.缓冲区长度count 。
read()函数是负责从fd中读取内容。
当读取成功时,read()返回实际所读的字节数,如果返回的值是0表示已经读到文件的结束了