多进程编程(终于来啦)

本文介绍了一个基于多进程处理客户端连接请求的服务器实现方法。通过创建子进程为每个客户端提供独立的服务,实现并发处理。文中详细介绍了服务器端代码,并展示了如何进行客户端测试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

提示:在前几篇文章的基础上,多进程编程终于来辣,被一些小事情和小错误耽误了不少的时间,属实是有点拖拉辣,🆗废话就到这,开始进入本篇正文


前言

这里主要写的是多进程的内容,如果有细节不理解,可以去看看前几篇文章或者针对不理解的地方再去查阅资料,或者与我私信也可以。


提示:以下是本篇文章正文内容,下面案例可供参考

一、多进程处理流程

附上一张流程图作一下简单的说明:
在这里插入图片描述

大致上看起来和迭代服务器(网络socket通信,前文有讲)的处理流程是很相似的,而它的不同之处在于,网络socket通信是属于“单”进程通讯,而真正的多进程通信是,一个服务器端,可以接收多个客户端的连接访问。

二、服务器端的示例代码

代码如下(示例):

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <getopt.h>
#include <ctype.h>

void print_usage(char *program)
{       
        printf("%s usage: \n",program);
        printf("-p(--port): sepcify server listen port.\n");
        printf("-h(--Help): print this help information.\n");
        return ;
}
int main(int argc,char **argv)
{
        int                     sockfd = -1;
        int                     rv = -1;
        struct sockaddr_in      servaddr;
        struct sockaddr_in      cliaddr;
        socklen_t               len;
        int                     port = 0;
        int                     clifd;
        int                     ch;
        int                     on = 1;
        pid_t                   pid;

        struct option   opts[] = {
                {"port",required_argument,NULL,'p'},
                {"help",no_argument,NULL,'h'},
                {NULL,0,NULL,0}
        };

        while(( ch = getopt_long(argc,argv,"p:h",opts,NULL))  != -1)
        {
                switch(ch)
                {
                        case 'p':
                                port = atoi(optarg);
                                break;
                        case 'h':
                                print_usage(argv[0]);
                                return 0;
                }
               }


        if( !port )
        {
                print_usage(argv[0]);

                printf("port is what: %d\n",port);
                printf("process is excuting now!!!!!!!!!!!!1");

                return 0;
        }

        sockfd = socket(AF_INET,SOCK_STREAM,0);

        if(sockfd < 0)
        {
                printf("create socket failure: %s\n",strerror(errno));
                return -1;
        }
        printf("create socket[%d] successfully!\n",sockfd);

        setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));

        memset(&servaddr,0,sizeof(servaddr));

        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(port);
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        //listen all the IP address on this host
        //inet_aton("192.168.0.16",&servaddr.sin_addr);
        //only listen specify IP address on this host

        rv = bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
        if( rv < 0 )
        {
                printf("Socket[%d] bind on port[%d] failureL %s\n",sockfd,port,strerror(errno));
                return -2;
        }

        listen(sockfd,13);
        printf("start to listen on port[%d]\n",port);
        while(1)
        {
                printf("start accept new client incoming!!!\n");

                clifd = accept(sockfd,(struct sockaddr *)&cliaddr,&len);
                if(clifd < 0)
                {
                        printf("accept new client failure: %s\n",strerror(errno));
                        continue;
                }
                printf("accept new client{%s:%d} succeddfully\n",inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port));

                pid = fork();
                if(pid < 0)
                {
                        printf("fork() create child process failure: %s\n",strerror(errno));
                        close(clifd);
                        continue;
                }
                else if( pid > 0 )
                {
                        //parent process close client fd goes to accept new socket client again
                        close(clifd);
                        continue;
                }
                else if( 0 == pid )
                {
                        char    buf[1024];
                        int     i;

                        printf("child process start to commuicate with socket client!!!\n");
                        close(sockfd);
                        //child process close the listen socket fd


                        while(1)
                        {

                                memset(buf,0,sizeof(buf));
                                rv = read(clifd,buf,sizeof(buf));
                                if(rv < 0)
                                {
                                        printf("read data from sockfd[%d] failure: %s\n",clifd,strerror(errno));
                                        close(clifd);
                                        exit(0);
                                }
                                else if(rv == 0)
                                {
                                        printf("socket[%d] get disconnet\n",clifd);
                                        close(clifd);
                                        exit(0);
                                }
                                else if(rv > 0)
                                {
                                        printf("read %d bytes data from server: %s\n",rv,buf);
                                }

                                //convert letter from lowercase to uppercase
                                for(i = 0; i < rv; i++)
                                {
                                        buf[i] = toupper(buf[i]);

                                }
                                rv = write(clifd,buf,rv);
                                if(rv < 0)
                                {
                                        printf("write to client by sockfd[%d] failure: %s\n",clifd,strerror(errno));
                                        exit(0);
                                }

                        }//child process loopp
                }//child process strat
        }
        close(sockfd);

        return 0;

三、客户端测试

在该处我使用了端口测试工具Tcp Test Tool,需要的可以和我私信。在服务器端运行的时候附上要监听的端口号。
在这里插入图片描述

在使用tcp test tool的时候,需要关闭防火墙,才能连接上,该程序可以开多个来模拟有多个客户端的效果,在本次测试中只需输入你的服务器端的ip地址和端口号就能在下面的框中输入信息并发送了,服务器端也会有相应的信息。如图:
在这里插入图片描述

四、代码中涉及到的一些函数

结构体option 的原型定义
代码如下(示例):

#define no_argument     0		//选项没有参数
#define required_argument  1		//选项需要参数
#define optional_argument  2		//选项参数可选

struct option {
   const char *name;	//不带短横线的选项名,前面没有短横线,如:help
   int has_arg;		//描述了选项是否有选项参数,其值可以是以上三个宏的任意一个值
   int *flag;			//用来决定,getopt_long()的返回值使什么	
   int val;
};

其中的*flag:
①指针为NULL:那么getopt_long()返回该结构体val字段中的数值;
②指针不为NULL: getopt_long()会使得它所指向的变量中填入val字段中的数值,并且getopt_long()返回0。
③如果flag不是NULL,但未发现长选项,那么它所指向的变量的数值不变。

setsockopt()函数
用于任意类型、任意状态套接字的设置选项值。尽管在不同协议层上存在选项,但本函数仅定义了最高的“套接字”层次上的选项。
函数原型:
Int setsockopt(int sockfd,int level, init optname,const void *optval, socklen_t optlen);

各参数的含义:
Sockfd:标识一个套接口的描述字;
Level:选项定义的层次;支持SOL_SOCKET、IPPROTO_TCP、IPPROTO_IP和IPPROTO_IPV6;
Optname:需设置的选项;
Optval:指针,指向存放选项待设置的新值的缓冲区。
Optlen:optval缓冲区的长度


总结

本文先到这

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值