UNP学习笔记-第5章
来源:互联网 发布:淘宝老a 编辑:程序博客网 时间:2024/05/21 20:22
1.server.c
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/socket.h>#include <arpa/inet.h>#include <sys/types.h>#include <signal.h>#include <errno.h>#include "proto.h"#define MAXLINE 1024static void sig_chld(int signo){ pid_t pid ; int stat; while((pid = waitpid(-1,&stat,WNOHANG)) >0) printf("child %d terminated\n",pid); return ;}static void str_echo(int sockfd){ ssize_t n; char buf[MAXLINE]; again: while((n = read(sockfd,buf,MAXLINE)) >0) write(sockfd,buf,n); if (n <0 && errno == EINTR) goto again; else if (n <0) { fprintf(stderr,"read error\n"); exit(1); } return ;}int main(int argc, char *argv[]){ int listenfd,connfd; pid_t pid; struct sockaddr_in laddr,raddr; socklen_t raddr_len; listenfd = socket(AF_INET,SOCK_STREAM,0); if(listenfd <0) { perror("socket()"); exit(1); } laddr.sin_family = AF_INET; laddr.sin_port = htons(atoi(SERVERPORT)); inet_pton(AF_INET,"0.0.0.0",&laddr.sin_addr); if(bind(listenfd,(void *)&laddr,sizeof(laddr)) <0) { perror("bind()"); exit(1); } if(listen(listenfd,200) <0) { perror("listen()"); exit(1); } signal(SIGCHLD,sig_chld); while(1) { raddr_len = sizeof(raddr); if((connfd = accept(listenfd,(void*)&raddr,&raddr_len)) <0) { if (errno == EINTR) continue; else { fprintf(stderr,"accept error"); exit(1); } } if((pid = fork()) == 0) { close(listenfd); str_echo(connfd); exit(1); } close(connfd); } return 0;}
在server程序中,还是按照约定 ,进行socket,bind,listen函数调用。在listen函数中,最大连接和未连接队列数设为200。
在listen函数返回之后,这里加入了信号处理函数 ,用于处理SIGCHLD信号。在信号处理函数中,使用 waitpid等待子进程的退出。WNOHANG告诉内核在没有已终止子进程时不要阻塞。
接着在while循环中,使用accept函数接受客户端的连接请求。不同于之前的程序,这里加入了对于被中断的系统调用的处理。即accept被中断后,恢复之前的系统调用。
而有一个函数不能重启,即connect函数,此时会使用select函数。在以后会有讲述。
适用于慢系统调用的基本规则是:当阻塞于某个慢系统调用的一个进程捕获某个信号且相应信号处理函数返回时,该系统调用可能返回一个EINTR错误。
接下来使用并发的方法,使用fork函数,使子进程来服务客户端。str_echo函数,将从客户端读取的消息,返回给客户端。
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/socket.h>#include <string.h>#include <arpa/inet.h>#include <sys/socket.h>#include "proto.h"#define MAXLINE 1024static void str_cli(FILE *fp,int sockfd){ char sendline[MAXLINE],recvline[MAXLINE]; while (fgets(sendline,MAXLINE,fp) != NULL) { write(sockfd,sendline,strlen(sendline)); if(read(sockfd,recvline,MAXLINE) == 0) { fprintf(stderr,"str_cli: server terminated prematurely"); exit(1); } fputs(recvline,stdout); } return;}int main(int argc , char *argv[]){ int i,sockfd[5]; struct sockaddr_in saddr; if(argc != 2) { fprintf(stderr,"Usage: ./client server_ip\n"); exit(1); } for (i=0;i<5;i++) { sockfd[i] = socket(AF_INET,SOCK_STREAM,0); if(sockfd[i] <0) { perror("socket()"); exit(1); } saddr.sin_family = AF_INET; saddr.sin_port = htons(atoi(SERVERPORT)); inet_pton(AF_INET,argv[1],&saddr.sin_addr); if(connect(sockfd[i],(void *)&saddr,sizeof(saddr))<0) { perror("connect()"); exit(1); } } str_cli(stdin,sockfd[0]); return 0;}
在client程序中,客户建立5个与服务器的连接。但是在调用str_cli函数时仅调用第一个连接。
在str_cli函数中,使用fgets函数从标准输入中读取用户输入,然后使用write函数写入到套接字sockfd中。
与服务器建立连接,从网络输入中读取这行文本,使用fputs显示在标准输出中。
更多细节参考UNIX Network Programming第五章。
- UNP学习笔记-第5章
- UNP学习笔记-第6章
- UNP学习笔记
- UNP 学习笔记
- UNP 学习笔记2
- UNP 学习笔记3
- UNP 学习笔记4
- UNP学习笔记(1)
- UNP学习笔记(2)
- UNP学习笔记(第二章:传输层)
- UNP学习笔记(第三章:套接字编程简介)
- UNP学习笔记(第六章 I/O复用)
- UNP学习笔记(第七章 套接字选项)
- UNP学习笔记(第六章 I/O复用)
- UNP学习笔记(第七章 套接字选项)
- UNP学习笔记(第十一章 名字与地址转换)
- UNP学习笔记(第十四章 高级I/O函数)
- UNP学习笔记(第十五章 UNIX域协议)
- C语言字符输出格式化
- Java的一些常见问题,JRE,JDK,JVM,包等概念理解
- ruby中的Hash排序
- 汇编指令大全(有注释)
- Mysql Explain 详解
- UNP学习笔记-第5章
- oracle 64为报错的问题
- 编程珠玑---读书笔记---第11章排序
- memset用法详解(转)
- Longest Valid Parentheses (求最长有效匹配括号子串的长度)
- Java Regular Expression Tutorial
- Android应用开发笔记(10):制作自定义背景Button按钮、自定义形状Button的全攻略
- iOS静态库相关-封装lib
- sizeof解析