3_並發服務器(多進程&多線程)

freeline-x 2022-01-08 03:29:02 阅读数:631

3_

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;
}
版权声明:本文为[freeline-x]所创,转载请带上原文链接,感谢。 https://gsmany.com/2022/01/202201080329018380.html