1.
#include <sys/socket.h>
int socket(int family, int type, int protocol);
//返回:若成功则返回非负描述符,出错则为-1,family是协议族,type表明套接字类型
family参数指定协议族,也被称为协议域。IPV4:AF_INET、IPV6:AF_INET6。
type参数指定套接字类型。字节流:SOCK_STREAM. 数据报:SOCK_DGRAM。
protocol参数是某个协议类型常值,或者设为0,以选择给定family和type组合的系统默认值。
TCP:IPPROTO_TCP , UDP:IPPROTO_UDP ,SCTP:IPPROTO_SCTP
2.
connect函数用来建立与TCP服务器的连接。
int connect (int sockfd , const struct sockaddr *servaddr , socklen_t addrlen);
成功:返回0,出错:返回-1
Sockfd: socket返回的套接字描述符;
*servaddr :指向套接字地址结构的指针;
Addrlen:套接字地址结构的大小;
其中出错可能有多种情况:
1.TCP客户没有收到SYN分节的响应,返回ETIMEOUT错误;
2.对客户的SYN的响应是RST(复位),表明主机在指定端口上没有进场等待连接,返回ECONNREFUSED错误;
对于TCP套接字,connect()会触发三次握手过程;当且仅当成功连接或出错时才会返回。其中出错可能有多种情况:
根据TCP转换图,connect()函数会使套接字从CLOSED状态转换到SYN_SENT状态,若成功再转换到ESTABLISHED状态。若connect失败,则该套接字不可再用,必须关闭,然后重新调用socket()函数。
3.
bind()函数把一个本地协议地址赋予一个套接字。(比如端口号)
Int bind (int sockfd ,const struct sockaddr *myaddr , soclen_t addrlen);
成功:返回0,出错:返回-1,还可能:Addrress already in use;
*myaddr:指向套接字地址结构的指针;
Addrlen:套接字地址结构的大小;
对于TCP客户:在该套接字上发送的IP数据报指派了源IP地址。
对于TCP服务器:限定该套接字只接收那些目的地为这个IP地址的客户连接。
4.
int listen (int sockfd , int backlog );
<1>当socket函数创建一个套接字时,它被假设为一个主动套接字(它将调用connect()函数发起连接),
<2>规定内核为相应套将字排队的最大连接个数。(backlog)
对backlog的理解:内核为每个监听套接字维护两个队列:
<1>未完成连接队列, <2>已完成连接队列
5.
int accept (int sockfd , struct sockaddr *cliaddr , socklen_t* addrlen);
成功:返回非负描述符,失败返回-1;
功能:由TCP服务器调用,用于从已完成连接队列队头返回下一个已完成连接。
*cliaddr、*addrlen:客户的协议地址及对应大小。
返回的描述符代表与所返回的客户的TCP连接,因此将sockfd称为监听套接字,将返回的描述符称为已连接套接字。
6.
int close( int sockfd);
关闭指定的套接字连接。可以忽略这个,直接exit(-1);
7.
intgetsockname (int sockfd , struct sockaddr *localaddr , socklen_t*addrlen);
intgetpeername (int sockfd , struct sockaddr *peeraddr , socklen_t*addrlen);
成功:返回0,出错返回-1;
功能:前者返回套接字的本地端的地址结构,后者返回外地端的地址结构。
只知道connfd的时候,获取客户身份的唯一途径就是调用getpeername。
<1>在没有调用bind的TCP客户上,connect()成功返回后,用getsockname()返回内核赋予该连接的本地IP地址和本地端口号;
<2>以端口号0调用bind(由内核选择本地端口号)后,用getsockname()返回本地端口号;
<3>getsockname可用于获取某个套接字的地址族;
<4>以通配IP地址调用bind的TCP服务器上,与客户的连接建立之后(accept成功返回),
getsockname用于返回内核赋予该连接的本地IP地址。(套接字描述符必须是已连接套接字描述符)
<5>当服务器通过调用accept的某个进程调用exec执行程序时,只能通过getpeername来获取客户身份。
8.
pid_t fork(void);
fork调用一次,在父进程中返回一次,得到子进程的进程ID号,在子进程返回一次,返回0.
父进程在fork之前打开的所以描述符在fork返回后由子进程分享。
如果父进程在fork后得到一个自身的副本,可以调用exec函数将当前进程映像替换成新的程序文件。称调用exec的进程为调用进程,新执行的程序为新程序。
exec函数只有在出错时才返回到调用者,否则,控制就被传递给新程序的起始点,通常是main函数