一、TCP简单流程图
因为对于server我已经写过一篇笔记了:http://www.cnblogs.com/ch122633/p/8315883.html
所以我想再补充一些对于client的部分的笔记、和fork相关的总结。
二、connect函数:
#include <sys/socket.h> int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen); 返回:0成功,-1出错
sockfd:套接字描述符
servaddr:套接口地址结构的指针
addrlen:该结构大小
客户在调用connect不必非调用bind,内核会选择源IP和临时端口。
connect函数会激发TCP三路握手过程,且仅在连接建立成功或出错时才返回。
bind函数:
#include <sys/socket.h> int bind(int sockfd, const struct sockaddr *myaddr, sockelt_t addrlen); 返回:0成功,-1出错
listen函数
#include <sys/socket.h> int listen(int sockfd, int backlog); 返回:0成功,-1出错
accept函数
#include <sys/socket.h> int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen); 返回:非负描述字OK,-1出错
三、fork和exec函数
#include <unistd.h> pid_t fork(void); 返回:在子进程中为0,在父进程中为子进程ID,-1出错
fork有两个典型应用:
1.进程创建自己的一个拷贝,当拷贝处理一个操作时,其他的拷贝可以执行其他任务。(网络)
2.一个进程想执行其他程序,犹豫创建新进程的唯一方法是调用fork,然后调用exec执行新程序。(shell)
#include <unistd.h> 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[]); 返回:-1出错,无返回成功
四、并发服务器
迭代服务器:大多数UDP服务器时迭代服务器,被单个客户长时间占用。
并发服务器:TCP服务器多使用,能同时服务多个客户。
pid_t pid; int listenfd, connfd; listenfd = Socket(...); /* fill in sockaddr_in{} with server's well-known port */ Bind(listenfd, ...); Listen(listenfd, LISTENQ); for(; ;) { connfd = Accept(listenfd, ...); /* probably blocks */ if((pid = Fork()) == 0) { Close(listenfd); /* child closes listening socket */ doit(connfd); /* process the request */ Close(connfd); /* done with this client */ exit(0); /* child terminates */ } Close(connfd); /* parent closes connected socket */ }
在服务器阻塞于accept调用、连接请求从客户到达时客户和服务器的状态。
从accept返回后,连接被内核接受,新的套接口即connfd被创建,这是一个已连接套接口,可由此通过连接读、写数据。
并发服务器下一步是调用fork,此时listenfd和connfd都是在父进程和子进程共享的。
一般套接口也用close关闭,终止TCP连接
#include <unistd.h> int close(int sockfd); 返回:0成功,-1出错
五、getsockname和getpeername函数
#include <sys/socket.h> int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen); int getpeername(int sockfd, struct sockaddr *peeraddr, socklen_t *addrlen); 返回:0成功,-1出错
getsockname返回套接口关联的本地协议地址
getpeername返回套接口关联的远程协议地址