1、多进程
1)父进程最大文件描述个数
2)系统内创建进程个数
3)进程创建过多是否降低整体服务性能
server端
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#define MAXLINE 80
#define SERV_PORT 800
void do_sigchild(int num)
{
while (waitpid(0,NULL,WNOHANG)>0)
;
}
int main(void)
{
struct sockaddr_in servaddr, cliaddr
socklen_t cliaddr_len;
int listenfd , connfd;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];
int i ,n
pid_t pid;
/*信号结构体*/
struct sigaction newact;
newact.sa_handler = do_sigchild;
/*sigemptyset(sigset_t *set)用来将参数set信号集初始化并清空。*/
sigemptyset (&newact.sa_mask);
newact.sa_flags = 0;
/*int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);*/
/*signum参数指出要捕获的信号类型,act参数指定新的信号处理方式,oldact参数输出先前信号的处理方式(如果不为NULL的话)*/
sigaction(SIGCHLD,&newact,NULL);
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);
bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
/*int listen(int sockfd, int backlog);最多允许20个处于连接状态*/
listen(listenfd,20);
printf("Accepting connections ... \n");
while(1){
cliaddr_len = sizeof(cliaddr);
connfd = accept(listenfd,(struct sockaddr*)&cliaddr,&cliaddr_len);
/*子进程中pid = 0,执行子进程程序,父进程中返回子进程的pid号*/
pid = fork();
if(pid == 0){ //子进程的程序
close(listenfd);
while(1){
n = read(connfd,buf,MAXLINE);
if(n == 0){
printf("the other side has been closed.\n");
break;
}
printf("received from %s at PORT %d\n",
inet_ntop(AF_INET,&cliaddr.sin_addr,str,sizeof(str)),
ntohs(cliaddr.sin_port));
for(i = 0;i<n;i++){
buf[i] = toupper(buf[i]);
}
write(connfd,buf,n);
}
close(connfd);
return 0;
}else if (pid > 0){//父进程的程序
close(connfd); //父进程只需要listefd,具体accept在子进程中进行
}else{
perr_exit("fork");
}
}
close(listenfd);
return 0;
}
client.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#define MAXLINE 80
#define SERV_PORT 6666
int main (int argc,char *argv[])
{
struct sockaddr_in servaddr;
char buf[MAXLINE];
int sockfd,n;
sockfd = socket(AF_INET,SOCK_STREAM,0);
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
/*ip地址转换函数,将点分10进制转换成二进制*/
inet_pton(AF_INET,"127.0.0.1",&servaddr.sin_addr);
servaddr.sin_port = htons(SERV_PORT);
connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
/*fgets从标准输入中读入字符串*/
while(fgets(buf,MAXLINE,stdin)!= NULL){
write(sockfd,buf,strlen(buf));
n = read(sockfd,buf,MAXLINE);
if(n == 0){
printf("the other side has benn closed.\n");
break;
}else{
write(STDOUT_FILENO,buf,n);
}
close(sockfd);
return 0;
}
}
2、多线程
1)调整进程内最大文件描述符上限
2)线程如有共享数据,考虑线程同步
3)服务于客户端线程退出时,退出处理(退出值,分离态)
4)系统负载,随着链接客户端增加,导致其他线程不能及时得到CPU
server.c
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
struct s_info {
struct sockaddr_in cliaddr;
int connfd;
};
void *do_work(void *arg)
{
int n ,i;
struct s_info *ts = (struct s_info*)arg;
char buf[MAXLINE];
char str[INET_ADDRSTRLEN];
/*可以在创建线程前设置线程创建属性,设为分离态,哪种效率高?*/
/*pthread_t pthread_self(void);
函数作用:获得线程自身的ID。pthread_t的类型为unsigned long int*/
/*pthread_detach(thread_id)(非阻塞,可立即返回)
这将该子线程的状态设置为detached,则该线程运行结束后会自动释放所有资源*/
pthread_detach(pthread_self());
while(1){
n = read(ts->connfd,buf,MAXLINE);
if(n == 0){
printf("the other side has been closed.\n");
break;
}
/*inet_ntop 将二进制转换为点分十进制*/
/*ntohs将一个16位数由网络字节顺序转换为主机字节顺*/
printf("received from %s at PORT %d\n",
inet_ntop(AF_INET,&(*ts).cliaddr.sin_addr,str,sizeof(str)),
ntohs((*ts).cliaddr.sin_port));
for(i = 0;i<n;i++)
{
/*int toupper(int c) 将字符c转换为大写字母*/
buf[i] = toupper(buf[i]);
write(ts->connfd,buf,n);
}
}
close(ts->connfd);
}
int main(void)
{
struct sockaddr_in servaddr,cliaddr;
socklen_t cliaddr_len;
int listenfd,connfd;
int i = 0;
pthread_t tid;
struct s_info ts[256];
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);
bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr));
listen(listenfd,20);
printf("Accepting connections ...\n");
while(1){
cliaddr_len = sizeof(cliaddr);
connfd = accept(listenfd,(struct sockaddr*)&cliaddr,&cliaddr_len);
ts[i].cliaddr = cliaddr;
ts[i].connfd = connfd;
/*当达到线程最大数时,pthread_create出错处理,增加服务器稳定性*/
pthread_create(&tid,NULL,do_work,(void*)&ts[i]);
i++;
}
return 0;
}
client.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#define MAXLINE 80
#define SERV_PORT 6666
int main(int argc,char *argv[])
{
struct sockaddr_in servaddr;
char buf[MAXLINE];
int sockfd,n;
sockfd = socket(AF_INET,SOCK_STREAM,0);
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_pton(AF_INET,"127.0.0.1",&servaddr.sin_addr);
servaddr.sin_port = htons(SERV_PORT);
connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr));
while(fgets(buf,MAXLINE,stdin)!=NULL){
write(sockfd,buf,strlen(buf));
n = read(sockfd,buf,MAXLINE);
if(n == 0)
{
printf("the other side has been closed.\n");
}else{
write(STDOUT_FILENO,buf,n);
}
}
close(sockfd);
return 0;
}