什么是套接字?
这里copy一下wiki上面的定义:一个应用程序接口(API),使用一个Internet套接字的概念,使主机间或者一台计算机上的进程间可以通讯。
TCP状态转换图
socket 函数
执行网络I/O,一个进程做的第一件事情、就是调用socket函数,指定期望的通信协议类型。
函数原型:
#include <sys/socket.h>
int socket (int family, int type, int protocol);
//返回:若成功则返回非负描述符,若出错则为-1
其中family指明协议族,family取值如下:
+---------------------------------------------
| family | 说 明
|---------------- | --------------------------
| AF_INET | IPv4协议
| AF_INET6 | IPv6协议
| AF_LOCAL | Unix域协议
| AF_ROUTE | 路由套接字
| AF_KEY | 秘钥套接字
+---------------------------------------------
type参数指明套接字类型,type取值如下:
+---------------------------------------------
| type | 说 明
|---------------- | --------------------------
| SOCK_STREAM | 字节流套接字
| SOCK_DGRAM | 数据报套接字
| SOCK_SEQPACKET | 有序分组套接字
| SOCK_PAM | 原始套接字
+---------------------------------------------
protocol为协议类型常值,取值如下:
+---------------------------------------------
| protocol | 说 明
|---------------- | --------------------------
| IPPROTO_TCP | TCP传输协议
| IPPROTO_UDP | UDP传输协议
| IPPROTO_SCTP | SCTP传输协议
+---------------------------------------------
当socket函数创建套接字后,TCP的状态为CLOSED。
connect 函数
TCP客户用connect函数来建立与TCP服务器的连接。
函数原型:
#include <sys/socket.h>
int connect (int sockfd, const struct sockaddr *seraddr, socklen_t addrlen);
sockfd是由socket()函数返回的套接字描述符,sockaddr为指向套接字地址结构的指针,addrlen为该地址结构的大小。套接字地址结构必须含有服务器的IP地址和端口号。
调用connect函数导致当前套接字从CLOSED转移到SYN_SENT状态,若调用成功则再进一步转移到ESTABLISHED状态。
bind 函数
bind函数把一个本地协议地址赋予一个套接字
函数原型:
#include <sys/socket.h>
int bind (int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);
//返回值情况:若成功则返回0,若失败则返回-1
bind函数其实与名字没有任何关系,它只是把一个协议地址赋予一个套接字,至于协议地址的含义则取决于协议本身。
参数sockaddr是一个指向特定于协议的地址的指针,参数addrlen是该地址结构的长度。
listen 函数
listen函数仅由TCP服务器调用,当被调用时,它完成两件事:
(1)当socket函数创建一个套接字时,被创建的套接字被假设为一个主动套接字,也就是说,它是一个将调用connect发起连接的客户套接字。listen函数把一个未连接的套接字转换成一个被动套接字,知识内核应接受指向该套接字的连接请求。根据TCP状态转换图,调用listen导致套接字从CLOSED状态转换到LISTEN状态。
(2)本函数的第二个参数规定了内核应该为相应的套接字排队的最大连接个数。
函数原型:
#include <sys/socket.h>
int listen (int sockfd, int backlog);
accept 函数
accept函数由TCP服务器调用,用于从已完成连接队列队列头返回下一个已完成连接。如果已完成连接为空,那么进程被投入睡眠。
函数原型:
#include <sys/socket.h>
int accept (int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);
//返回值情况:若成功则为非负描述符,若出错则为-1
参数cliaddr和addrlen用来返回已连接的对端进程(客户)的协议地址。addrlen是值-结果参数,至于什么是值-结果参数,这里就不展开说明了,有兴趣的可以google下。
如果accept函数调用成功,其返回值是由内核自动生成的一个全新描述符,代表与所返回客户的TCP连接。accept函数的第一个参数为监听套接字描述符,称它的返回值为已连接套接字。一个服务器通常仅仅创建一个监听套接字,它在该服务器的生命期内一直存在。每个由服务器进城接受的客户连接,内核都会为它创建一个已连接套接字。当服务器完成对某个给定客户的服务时,相应的已连接套接字就被关闭。
close 函数
close函数用来关闭套接字,并终止TCP连接。
函数原型:
#include <unistd.h>
int close (int sockfd);
//返回值情况:若成功则为0,若出错则为-1
close一个TCP套接字的默认行为是把该套接字标记成已关闭,然后立即返回到调用进程。该套接字描述符不能再由调用进程使用,也就是说它不能再作为read函数或write函数的第一个参数。
注:该篇博客参考自《UNIX网络编程 卷一》