多进程模型
demo 多线程模型
demo
先read 函数的返回值 非常重要
> 0 实际读到的字节数 = 0 已经读到结尾(对端已经关闭) -1 应进一步判断errno的值:重要!!! -1一定要进行判断,否则接收端一直在接收 errno = EAGAIN or EWOULDBLOCK 设置了非阻塞方式读,没有数据到达。 errno = EINTR 慢速系统调用被 中断。 errno = “其他情况” 异常。多进程模型
socket()
bind()
listen()
//catch sigchild signal 回收子进程
while(1)
{
cfd=accept()
pid=fork()
if(pid==0)//child process
{
close(lfd)
read()/write()
}
else if(pid > 0)//parent process
{
close(cfd)
}
else
{
//error
}
}
demo
#include多线程模型#include #include #include #include #include #include #include #include #include #include #include #include #include #define SERVER_PORT 6666 #define MAXLINE 1024 void catch_child(int signum) { while(waitpid(0,NULL,WNOHANG) > 0); return; } static void sys_error(const char *str) { perror(str); exit(1); } int main(int argc,char *argv[]) { int lfd = 0,cfd = 0; int ret; char buffer[BUFSIZ],client_ip[56]; pid_t pid; char str[1024]; struct sockaddr_in serv_addr,clit_addr; socklen_t clit_addr_len,client_ip_len; //signal struct sigaction act; act.sa_handler = catch_child; sigemptyset(&act.sa_mask); act.sa_flags = 0; ret = sigaction(SIGCHLD,&act,NULL); if(ret != 0) { sys_error("sigaction error"); } serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(SERVER_PORT); serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); lfd = socket(AF_INET,SOCK_STREAM,0); if(lfd == -1) sys_error("socket error"); int opt = 1; setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)); bind(lfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)); listen(lfd,128); socklen_t client_addrlength = sizeof(clit_addr); client_addrlength = sizeof(clit_addr); while(1){ cfd = accept(lfd,(struct sockaddr *)&clit_addr,&client_addrlength); if(cfd < 0) { printf("error is:%dn",errno); } pid = fork(); if (pid == 0) {//child close(lfd); while (1) { ret = read(cfd, buffer, MAXLINE); if (ret == 0) { printf("the other side has been closed.n"); break; } else if(ret == -1) { //printf("str=%sn", strerror(errno)); if (errno == EINTR) continue; else return -1; } write(cfd, buffer, ret); } close(cfd); return 0; } else if (pid > 0) {//parent close(cfd); } else { perror("error exitn"); exit(-1); } } return 0; }
socket()
bind()
listen()
while(1)
{
cfd = accept(lfd,);
pthread_create(&pid,NULL,fun,(void* )cfd);
prhread_detach(tid);//子线程分离
}
//child pthead
void *fun()
{
read()/write()
pthread_exit();
}
demo
#include#include #include #include #include #include #include #include #define MAXLINE 1024 #define SERV_PORT 6666 struct s_info { struct sockaddr_in cliaddr; int connfd; }; void *work_pthread(void *arg) { int n,i; struct s_info *ts = (struct s_info*)arg; char buf[MAXLINE]; char str[INET_ADDRSTRLEN]; while (1) { n = read(ts->connfd, buf, MAXLINE); if (n == 0) { printf("the client %d closed...n", ts->connfd); break; } else if(ret == -1) { //printf("str=%sn", strerror(errno)); if (errno == EINTR) continue; else return -1; } write(ts->connfd, buf, n); //回写 } close(ts->connfd); return (void *)0; } int main(void) { struct sockaddr_in servaddr, cliaddr; socklen_t cliaddr_len; int listenfd, connfd; pthread_t tid; struct s_info ts[256]; int i = 0; listenfd = socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT); int opt = 1; setsockopt(listenfd ,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)); bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); listen(listenfd, 128); printf("Accepting client connect ...n"); while (1) { cliaddr_len = sizeof(cliaddr); connfid = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len); if(connfid < 0) { printf("error is %dn",errno); } ts[i].cliaddr = cliaddr; ts[i].connfd = connfd; pthread_create(&tid, NULL, work_pthread, (void*)&ts[i]); pthread_detach(tid); i++; } return 0; }
端口复用,在断开连接后,端口号可以再次被使用,否则要等到40多秒
int opt = 1; setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));



