Linux网络编程并发服务器

linux网络编程并发服务器开发

一、多进程并发服务器

1.1 多进程程并发服务器的原理:

多进程并发服务器就是当客户端发来请求时,开辟一个子进程用来处理客户端请求,主进程用来循环等待接受其它客户端的请求。这样做的好处就是服务器可以的处理客户端的请求,当有客户端退出时,给父进程发送一个SIGCHID信号,然后父进程来回收子进程的资源,与此同时服务器还是可以接收新的客户端请求,大大的提高了服务器的性能。

1.2 多进程并发服务器开发步骤

1)创建套接字socket()
2)绑定网络和地址bind()
3)设置监听套接字listen()
4)接受服务器连接accept()
5)处理客户端请求
6)关闭套接字colse()

先看一下伪代码整理一下思路

void fun();  //处理子进程的函数
int main()
{
	socket();
	bind();
	listen();
	while(1)
	{
		connfd = accept();
		pid = fork();  //创建一个子进程来处理客户端
		if(pid == 0)
		{
			close(sockfd); //关闭监听套接字sockfd
			/*判断退出*/
			kill(getppid(), SIGCHID);
			/* 数据处理 */
			close(connfd);   //数据处理完成后关闭通信套接字
			exit(0);   //子进程退出
		}
		else
		{
			fun();
			close(connfd);
		}
	}

1.3 多进程并发服务器开发

服务器端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <wait.h>
#include <signal.h>
#define N 128

/*
 *  多进程并发服务器端
 **/
 
//子进程回收函数
void ChildFunc()
{
   wait(NULL);
}
int main(int argc, char *argv[])
{
    //创建套接字
    socklen_t sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd == -1)
    {
        perror("socket");
        return -1;
    }
    printf("socket is ok\n");
    
    //绑定
    struct sockaddr_in seraddr, cliaddr;
    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(8888);
    seraddr.sin_addr.s_addr = inet_addr("0.0.0.0");
    
    if(bind(sockfd, (struct sockaddr*)&seraddr, sizeof(seraddr)) == -1)
    {
        close(sockfd);
        perror("bind");
        return -1;
    }
    printf("bind is ok\n");
    
    //设置监听
    if(listen(sockfd, 1024) == -1)
    {
        perror("listen");
        return -1;
    }
    printf("listen is ok\n");
    
    //接受连接
    int connfd;
    int len =sizeof(struct sockaddr);
    while(1)
    {
        connfd = accept(sockfd, (struct sockaddr*)&cliaddr, &len);
        pid_t pid = fork();
        if(pid < 0)
        {
            perror("fork");
            exit(-1);
        }
        else if(pid == 0)
        {
            /*
             * 子进程用来处理客户端的请求
             * */
            char recv_buf[N] = {0};
            int recv_len = 0;
            //关闭从父进程继承来的套接字,节省资源,并且可以避免发生不可预知的错误
            close(sockfd);
            //打印客户端的信息
            printf("**********     Client Message   **********\n");
            printf("CLient IP:%s\t", inet_ntoa(cliaddr.sin_addr));
            printf("Client Post:%d\n", ntohs(cliaddr.sin_port));

            //接收数据
            while(1)
            {
                recv_len = recv(connfd, recv_buf, sizeof(recv_buf), 0);
                //如果没有接收到信息,或者收到quit退出信号,关闭客户端
                if(recv_len <=0 ||strncmp(recv_buf, "quit", 4) == 0)
                {
                    printf("Client closed\n");
                    close(connfd);
                    //发送SIGCHID信号,让父进程来回收子进程的资源
                    kill(getppid(), SIGCHLD);
                    break;
                }
                printf("recv_buf: %s\n", recv_buf);
                //给客户端发送数据
                send(connfd, "hello\n", recv_len, 0);
            }
            exit(0);
        }
        else
        {
            //父进程
            signal(SIGCHLD,ChildFunc);
            close(connfd);
        }
    }
    //关闭套接字
    close(sockfd);
    return 0;
}
客户端

测试用客户端代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <wait.h>
#include <signal.h>
#define N 128

/*
 *  进程并发客户端
 **/
//子进程回收函数
int main(int argc, char *argv[])
{
    //创建套接字
    socklen_t sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd == -1)
    {
        perror("socket");
        return -1;
    }
    printf("socket is ok\n");
    //绑定
    struct sockaddr_in seraddr;
    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(8888);
    //自动获取主机地址
    seraddr.sin_addr.s_addr = inet_addr("192.168.2.113");

    if(connect(sockfd, (struct sockaddr*)&seraddr, sizeof(seraddr)) == -1)
    {
        close(sockfd);
        perror("connect");
        return -1;
    }
    printf("connect is ok\n");
    //进行数据交互
    int ret = 0;
    while(1)
    {
        char buf[32] = {0};
        fgets(buf, 32, stdin);
        printf("%s", buf);
        //设置一个出口
        if(strncmp("quit", buf, 4) == 0)
        {
            break;
        }
        buf[strlen(buf)-1] = '\0';
        write(sockfd, buf, sizeof(buf));
        memset(buf, 0, 32);
        ret = read(sockfd, buf, sizeof(buf));

        if(ret == 0)
        {
            printf("Client close\n");
            return -1;
        }
        printf("Server:%s\n", buf);
    }
    //关闭套接字
    return 0;
}

二、多线程并发服务器

每当客户端发来连接请求(accpet到一个句柄),主线程会开辟一个子线程去处理请求,

三、IO多路复用

后续补充。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值