socket函数
#include <sys/socket.h>
int socket(int family, int type, int protocol);
family(协议域):AF_INET(ipv4协议),AF_INET6(ipv6协议),AF_LOCAL(Unix协议域),AF_ROUTE(路由套接字),AF_KEY(密钥套接字)
type(套接字类型):SOCK_STREAM(字节流套接字),SOCK_DGRAM(数据报套接字),SOCK_SEQPACKET(有序分组套接字),SOCK_RAW(原始套接字)
protocol(协议类型,设为0表示选择给定family和type组合的系统默认值):IPPROTO_TCP(TCP传输协议),IPPROTO_UDP(UDP传输协议),IPPROTO_SCTP(SCTP传输协议)
函数在成功时返回一个小的非负整数值,我们称之为套接字描述符(socket descriptor),简称sockfd,若出错则返回-1。
注:
1、type与protocol并不是可以任意组合,如TCP是一个字节流协议,仅支持SOCK_STREAM套接字
2、参数family和type还有其他值,如Linux支持一个新的套接字类型SOCK_PACKET
3、调用socket时会碰到PF_值,历史上AF_前缀表示地址族,PF_前缀表示协议族,但现在可看作一个东西。
connect函数
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);
sockfd:socket函数返回的套接字描述符
第二个参数为指向套接字结构的指针,第三个参数为该结构的大小,套接字地址结构必须含有服务器的IP地址和端口号。
如果是TCP套接字,调用connect函数将激发TCP的三路握手过程。
bind函数
#include <sys/socket.h>
//bind函数把一个本地协议地址赋予一个套接字,对于网际协议,协议地址是IP地址与TCP或者UDP端口号的组合
int bind(int sockfd, const struct sockaddr *myaddr, socklen_t addrlen);
调用bind函数可以指定一个端口号,或者指定一个IP地址,也可以两者都指定,还可以都不指定
listen函数
int listen(int socketfd, int backlog);
做两件事:
1)当socket函数创建一个套接字时,它被假设为一个主动套接字,也就是说,它是一个将调用connect发起连接的客户套接字,listen函数把一个未连接的套接字转换成一个被动套接字,指示内核接收指向该套接字的连接请求。
2)本函数的第二个参数规定了内核应该为相应套接字排队的最大连接个数。
内核为任何一个给定的监听套接字维持两个队列:
a)未完成连接队列
b)已完成连接队列
accept函数
int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);
fork和exec函数
#include <unistd.h>
//返回:在子进程中为0,在父进程中为进程ID,若出错则为-1
pid_t fork(void);
典型用法:
1)一个进程创建一个自身的副本,这样每个副本都可以在另一个副本执行其他任务的同时处理各自的某个操作。这是网络服务器的典型用法
2)一个进程想要执行另一个程序。
6个exec函数:
//均返回:若成功则不返回,若出错则为-1
int execl(const char *pathname, const char *arg0, ... /* (char *) 0 */);
int execv(const char *pathname, char *const *argv[ ]);
int execle(const char *pathname, const char *arg0, ... /* (char *) 0, char *const envp[ ] */);
int execve(const char *pathname, char *const argv[ ], char *const envp[ ]);
int execlp(const char *filename, const char *arg0, ... /* (char *) 0 */ );
int execvp(const char *filename, char *const argv[ ]);
区别:
a)待执行程序文件是由文件名(filename)还是由路径名(pathname)指定;
b)新程序的参数是一一列出还是由一个指针数组来引用;
c)把调用进程的环境传递给新程序还是给新程序指定新的环境;
这些函数只在出错时才返回到调用者,否则,控制将被传递给新程序的起始点,通常就是main函数。
execlp(file, arg, ..., 0) execl(path, arg, ..., 0)execle(path, arg, ..., 0, envp)
|创建argv |创建argv |创建argv
execvp(file, argv) execv(path, argv)execve(path, argv, envp)
6个函数的区别:
1)上面一行3个函数把新程序的每个参数字符串指定成exec的一个独立参数,并以一个空指针结束可变数量的这些参数;下面一行3个函数都有一个作为exec参数的argv数组,其中含有指向新程序各个参数字符串的所有指针,既然没有指定参数字符串的数目,这个argv数组必须含有一个用于指定其末尾的空指针。
2)左列2个函数指定一个filename参数,exec将使用当前的PATH环境变量把该文件名参数转换为一个路径名,然而一旦这个filename参数中含有一个斜杠(/),就不再使用PATH环境变量,右两列4个函数指定一个全限定的pathname参数;
3)左两列4个函数不显示指定一个环境指针,相反,它们使用外部变量environ的当前值来构造一个传递给新程序的环境列表,右列2个函数显示指定一个环境列表,其envp指针数组必须以一个空指针结束。
close函数
int close(int sockfd);
getsockname和getpeername函数
#include <sys/socket.h>
//返回与某个套接字关联的本地协议地址,成功返回0,出错返回-1
int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen);
//返回与某个套接字关联的外地址协议
int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen);