实现多线程并发服务器和多进程并发服务器(Linux网络编程)

多进程并发服务器

实现流程

	1. Socket();		创建 监听套接字 lfd
	2. Bind()	绑定地址结构 Strcut scokaddr_in addr;
	3. Listen();	
	4. while (1) {

		cfd = Accpet();			接收客户端连接请求。
		pid = fork();
		if (pid == 0){			子进程 read(cfd) --- 小写->大写 --write(cfd)			

			close(lfd)		关闭用于建立连接的套接字 lfd

			read()
			//小写转大写代码
			write()

		} else if (pid > 0{	

			close(cfd);		关闭用于与客户端通信的套接字 cfd	
			continue;
		}
	  }

	5. 子进程:

		close(lfd)

		read()

		小写->大写

		write()	

	   父进程:

		close(cfd);

		注册信号捕捉函数:	SIGCHLD

		在回调函数中, 完成子进程回收

			whilewaitpid();

read 函数的返回值:

	1. > 0 实际读到的字节数

	2. = 0 已经读到结尾(对端已经关闭)【 !重 !点 !】

	3. -1 应进一步判断errno的值:

		errno = EAGAIN or EWOULDBLOCK: 设置了非阻塞方式 读。 没有数据到达。 

		errno = EINTR 慢速系统调用被 中断。

		errno = “其他情况” 异常。

代码

#include <stdio.h>  
#include <ctype.h>  
#include <stdlib.h>  
#include <sys/wait.h>  
#include <string.h>  
#include <strings.h>  
#include <unistd.h>  
#include <errno.h>  
#include <signal.h>  
#include <sys/socket.h>  
#include <arpa/inet.h>  
#include <pthread.h>  
  
#include "wrap.h"  
  
#define SRV_PORT 9999  
  
void catch_child(int signum)  
{  
    while ((waitpid(0, NULL, WNOHANG)) > 0);  
    return ;  
}  
  
int main(int argc, char *argv[])  
{  
    int lfd, cfd;  
    pid_t pid;  
    struct sockaddr_in srv_addr, clt_addr;  
    socklen_t clt_addr_len;   
    char buf[BUFSIZ];  
    int ret, i;  
  
    //memset(&srv_addr, 0, sizeof(srv_addr));                 // 将地址结构清零  
    bzero(&srv_addr, sizeof(srv_addr));  
  
    srv_addr.sin_family = AF_INET;  
    srv_addr.sin_port = htons(SRV_PORT);  
    srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);  
  
    lfd = Socket(AF_INET, SOCK_STREAM, 0);  
  
    Bind(lfd, (struct sockaddr *)&srv_addr, sizeof(srv_addr));  
  
    Listen(lfd, 128);  
  
    clt_addr_len = sizeof(clt_addr);  
  
    while (1) {  
  
        cfd = Accept(lfd, (struct sockaddr *)&clt_addr, &clt_addr_len);  
  
        pid = fork();  
        if (pid < 0) {  
            perr_exit("fork error");  
        } else if (pid == 0) {  
            close(lfd);  
            break;          
        } else {  
            struct sigaction act;  
  
            act.sa_handler = catch_child;  
            sigemptyset(&act.sa_mask);  
            act.sa_flags = 0;  
  
            ret = sigaction(SIGCHLD, &act, NULL);  
            if (ret != 0) {  
               perr_exit("sigaction error");  
            }  
            close(cfd);   
            continue;  
        }  
    }  
  
    if (pid == 0) {  
        for (;;) {  
            ret = Read(cfd, buf, sizeof(buf));  
            if (ret == 0) {  
                close(cfd);  
                exit(1);  
            }   
  
            for (i = 0; i < ret; i++)  
                buf[i] = toupper(buf[i]);  
  
            write(cfd, buf, ret);  
            write(STDOUT_FILENO, buf, ret);  
        }  
    }  
  
    return 0;  
}  

多线程并发服务器

实现流程

1. Socket();		创建 监听套接字 lfd

	2. Bind()		绑定地址结构 Strcut scokaddr_in addr;

	3. Listen();		

	4. while (1) {		

		cfd = Accept(lfd, );

		pthread_create(&tid, NULL, tfn, (void *)cfd);

		pthread_detach(tid);  				// pthead_join(tid, void **);  新线程---专用于回收子线程。
	  }

	5. 子线程:

		void *tfn(void *arg) 
		{
			// close(lfd)			不能关闭。 主线程要使用lfd

			read(cfd)--write(cfd)

			pthread_exit((void *)10;	
		}

代码

#include <stdio.h>  
#include <string.h>  
#include <arpa/inet.h>  
#include <pthread.h>  
#include <ctype.h>  
#include <unistd.h>  
#include <fcntl.h>  
  
#include "wrap.h"  
  
#define MAXLINE 8192  
#define SERV_PORT 8000  
  
struct s_info {                     //定义一个结构体, 将地址结构跟cfd捆绑  
    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];      //#define INET_ADDRSTRLEN 16  可用"[+d"查看  
  
    while (1) {  
        n = Read(ts->connfd, buf, MAXLINE);                     //读客户端  
        if (n == 0) {  
            printf("the client %d closed...\n", ts->connfd);  
            break;                                              //跳出循环,关闭cfd  
        }  
        printf("received from %s at PORT %d\n",  
                inet_ntop(AF_INET, &(*ts).cliaddr.sin_addr, str, sizeof(str)),  
                ntohs((*ts).cliaddr.sin_port));                 //打印客户端信息(IP/PORT)  
  
        for (i = 0; i < n; i++)   
            buf[i] = toupper(buf[i]);                           //小写-->大写  
  
        Write(STDOUT_FILENO, buf, n);                           //写出至屏幕  
        Write(ts->connfd, buf, n);                              //回写给客户端  
    }  
    Close(ts->connfd);  
  
    return (void *)0;  
}  

2.int main(void)  
3.{  
4.    struct sockaddr_in servaddr, cliaddr;  
5.    socklen_t cliaddr_len;  
6.    int listenfd, connfd;  
7.    pthread_t tid;  
8.  
9.    struct s_info ts[256];      //创建结构体数组.  
10.    int i = 0;  
11.  
12.    listenfd = Socket(AF_INET, SOCK_STREAM, 0);                     //创建一个socket, 得到lfd  
13.  
14.    bzero(&servaddr, sizeof(servaddr));                             //地址结构清零  
15.    servaddr.sin_family = AF_INET;  
16.    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);                               //指定本地任意IP  
17.    servaddr.sin_port = htons(SERV_PORT);                                       //指定端口号   
18.  
19.    Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));             //绑定  
20.  
21.    Listen(listenfd, 128);                                                      //设置同一时刻链接服务器上限数  
22.  
23.    printf("Accepting client connect ...\n");  
24.  
25.    while (1) {  
26.        cliaddr_len = sizeof(cliaddr);  
27.        connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);   //阻塞监听客户端链接请求  
28.        ts[i].cliaddr = cliaddr;  
29.        ts[i].connfd = connfd;  
30.  
31.        pthread_create(&tid, NULL, do_work, (void*)&ts[i]);  
32.        pthread_detach(tid);                                                    //子线程分离,防止僵线程产生.  
33.        i++;  
34.    }  
35.  
36.    return 0;  
37.}  

最近更新

  1. TCP协议是安全的吗?

    2024-05-02 22:32:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-05-02 22:32:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-05-02 22:32:01       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-05-02 22:32:01       20 阅读

热门阅读

  1. 图搜索算法详解

    2024-05-02 22:32:01       12 阅读
  2. Golang Colly下载小红书详情页面图片小爬虫

    2024-05-02 22:32:01       16 阅读
  3. 微服务是什么

    2024-05-02 22:32:01       10 阅读
  4. DFR初识

    DFR初识

    2024-05-02 22:32:01      13 阅读
  5. 2023-2024年Web3行业报告合集(精选13份)

    2024-05-02 22:32:01       13 阅读
  6. 76. 最小覆盖子串

    2024-05-02 22:32:01       10 阅读
  7. CSS的box-shadow 用法

    2024-05-02 22:32:01       13 阅读
  8. 高可用系列三:事务

    2024-05-02 22:32:01       11 阅读
  9. Dubbo源码解读-Mock原理和消费端服务列表刷新

    2024-05-02 22:32:01       12 阅读