Linux下多进程服务端客户端模型一(单进程与多进程模型)

本文将会简单介绍Linux下如何利用C库函数与系统调用编写一个完整的、初级可用的C-S模型。

一、基本模型:

1.1   首先服务器调用socket()函数建立一个套接字,然后bind()端口,开始listen()监听,此时,套接字变成了被动的套接字,用于侦听客户端的请求。然后accept(),开始阻塞监听客户端的请求。

  1.2   客户端以服务端的参数为参数,用socket()建立套接字,然后connect()连接服务端。

1.3  服务端收到连接请求,accept()返回一个标识符,继续执行后面的指令。具体如图:

1.4  服务端创建套接字与绑定端口代码(打码处为点分十进制的IP字符串,注意,端口号用函数转换成网络传输的大端的Long类型,点分十进制IP转换成二进制。):

1.5 服务端监听与accept,并且循环读写代码:

while结束后close(conn)  close(sockfd)即可。

1.6 客户端(打码处为服务端的IP与端口)

二、多进程

2.1

由于accept是阻塞的函数,如果用单进程进行,那么将会只能接受一个客户端的请求。而对于其他客户端的请求,则代码不会返回去重新执行accept();

     要注意的是,其他客户端连接服务器时,即使服务器只接受一个客户端的业务请求,但是内核会帮我们完成TCP的三次握手连接,放入已连接的队列中等待服务器的accept去取走,不过,由于我们没有开启新的进程,所以,后来的这些连接没有机会被取走了。如图:

2.2

 针对以上问题,可以将accept()放入while循环中,然后每一次接收到了连接,则创建一个子进程,然后子进程去执行读写操作,而父进程则继续监听。代码如下:

 1 #include <unistd.h>
 2 #include <sys/stat.h>
 3 #include <sys/wait.h>
 4 #include <sys/types.h>
 5 #include <fcntl.h>
 6
 7 #include <stdlib.h>
 8 #include <stdio.h>
 9 #include <errno.h>
10 #include <string.h>
11 #include <signal.h>
12
13 #include <arpa/inet.h>
14 #include <sys/socket.h>
15 #include <netinet/in.h>
16
17 int main(void)
18 {
19     int sockfd;
20     // 创建一个Socket
21     sockfd = socket(AF_INET,SOCK_STREAM,0);
22     if(sockfd == -1){
23         perror("error");
24         exit(0);
25     }
26
27
28     ///////////////////////////////////////////////////////////
29 //    struct sockaddr addr; // 这是一个通用结构,一般是用具体到,然后转型
30     struct sockaddr_in sockdata;
31     sockdata.sin_family = AF_INET;
32     sockdata.sin_port = htons(8001);
33     sockdata.sin_addr.s_addr = inet_addr(我是IP字符串);
34
35     int optval = 1;
36     if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval)) == -1)
37     {
38         perror("error");
39         exit(0);
40     }
41     if(bind(sockfd,(struct sockaddr *)&sockdata,sizeof(sockdata)) < 0){
42         perror("error");
43         exit(0);
44     }
45
46     ////////////////////////////////////////////////////////////
47     if(listen(sockfd,5) == -1){
48         perror("error");
49         exit(0);
50     }
51
52     //////////////////////////////////////////////////////////
53     struct sockaddr_in peeradr;
54     socklen_t peerlen = sizeof(peeradr); // 得有初始值
55
56
57     /////////////////////////////////////////////////////////
58     char recvBuff[1024]={0};
59     int conn = 0;
60     while(1){
61         conn = accept(sockfd,(struct sockaddr *)&peeradr,&peerlen);
62         if(conn == -1){
63             perror("error");
64             exit(0);
65         }
66         // 每来一个链接fork一个进程。
67         pid_t pid;
68         pid = fork();
69
70         if(pid == 0){
71             int ret = 0;
72             close (sockfd); // 由于子进程复制来sockfd,所以关掉它。 不干涉父进程来,因为这是一个副本。由父进程继续监听
73             printf("收到的IP %s\n 客户端端口是:%d\n",inet_ntoa(peeradr.sin_addr),ntohs(peeradr.sin_port));
74             while((ret = read(conn,recvBuff,sizeof(recvBuff))) && ret > 0){
75                 // 服务器收到打印数据,然后回发
76                 fputs(recvBuff,stdout);
77                 write(conn,recvBuff,ret);
78             }
79             exit(0);
80         }
81         else if(pid > 0){
82             close(conn); // 父进程只管监听,不需要链接套接字!!
83         }
84         else{
85             perror("error");
86             close(conn);
87             close(sockfd);
88             exit(0);
89         }
90     }
91     close(conn);
92     close(sockfd);
93     return 0;
94 }

server.c

而客户端没有什么变化,代码如下:

 1 #include <unistd.h>
 2 #include <sys/stat.h>
 3 #include <sys/wait.h>
 4 #include <sys/types.h>
 5 #include <fcntl.h>
 6
 7 #include <stdlib.h>
 8 #include <stdio.h>
 9 #include <errno.h>
10 #include <string.h>
11 #include <signal.h>
12
13 #include <arpa/inet.h>
14 #include <sys/socket.h>
15 #include <netinet/in.h>
16
17 int main(void)
18 {
19         int sockfd;
20     // 创建一个Socket
21     sockfd = socket(AF_INET,SOCK_STREAM,0);
22     if(sockfd == -1){
23         perror("error");
24         exit(0);
25     }
26
27
28     ///////////////////////////////////////////////////////////
29 //    struct sockaddr addr; // 这是一个通用结构,一般是用具体到,然后转型
30     struct sockaddr_in sockdata;
31     sockdata.sin_family = AF_INET;
32     sockdata.sin_port = htons(8001);
33     sockdata.sin_addr.s_addr = inet_addr("我是IP字符串");
34     if(connect(sockfd,(struct sockaddr *)&sockdata,sizeof(sockdata)) == -1){
35         perror("error");
36         exit(0);
37     }
38
39     char sendBuff[1024] = {0};
40     char recvBuff[1024] = {0};
41
42     while(fgets(sendBuff,sizeof(sendBuff),stdin) != NULL){
43         // 将输入到数据送到服务端
44         write(sockfd,sendBuff,sizeof(sendBuff));
45         // 从服务器读数据
46         read(sockfd,recvBuff,sizeof(recvBuff));
47
48         // 显示在屏幕上
49         fputs(recvBuff,stdout);
50         // 清零
51         memset(recvBuff,0,sizeof(recvBuff));
52         memset(sendBuff,0,sizeof(sendBuff));
53     }
54
55     close(sockfd);
56     return 0;
57 }

client.c

时间: 2024-10-11 06:42:08

Linux下多进程服务端客户端模型一(单进程与多进程模型)的相关文章

Linux下多进程服务端客户端模型二(粘包问题与一种解决方法)

一.Linux发送网络消息的过程 (1) 应用程序调用write()将消息发送到内核中 ( 2)内核中的缓存达到了固定长度数据后,一般是SO_SNDBUF,将发送到TCP协议层 (3)IP层从TCP层收到数据,会加上自己的包头然后发送出去.一般分片的大小是MTU(含IP包头),而IPV4下IP的包头长度为40,而IPV6下为60,因此,TCP中分片后,有效的数据长度为MSS = MTU - 40 或 MSS = MTU -60 (4)最终经过其他层的包装,发送到公网上,跑来跑去,这时候,你的数据

Linux下smba服务端的搭建和客户端的使用

解决了 windows下用root登录linuxsamba后有部分目录访问无权限的问题.应该是SELinux 设置问题. 对selinux进行修改,一般为终止这项服务,操作如下: 查看SELinux状态: 1./usr/sbin/sestatus -v ##如果SELinux status参数为enabled即为开启状态 SELinux status: enabled 2.getenforce ##也可以用这个命令检查 关闭SELinux: 1.临时关闭(不用重启机器): setenforce

c++ 网络编程(四)TCP/IP LINUX/windows下 socket 基于I/O复用的服务器端代码 解决多进程服务端创建进程资源浪费问题

原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/9613861.html 好了,继上一篇说到多进程服务端也是有缺点的,每创建一个进程就代表大量的运算与内存空间占用,相互进程数据交换也很麻烦. 本章的I/O模型就是可以解决这个问题的其中一种模型...废话不多说进入主题-- I/O复用技术主要就是select函数的使用. 一.I/O复用预备知识--select()函数用法与作用 select()用来确定一个或多个套接字的状态(更为本质一点来讲是文

Linux下的TCP/IP编程----进程及多进程服务端

在之前的学习中我们的服务端同一时间只能为一个客户端提供服务,即使是将accept()函数包含在循环中,也只能是为多个客户端依次提供服务,并没有并发服务的能力,这显然是不合理的.通过多进程的使用,我们可以很便捷的实现服务端的多进程,这样就可以同时为多个客户端提供服务. 首先我们要理解程序,进程,进程ID,僵尸进程,线程的概念. 程序:广泛的说就是为了达到某一目的二规定的途径,在编程中具体的就是为了实现某一功能而编写的代码实体,是静态的. 进程:程序的一次动态执行就是一个进程,它是占用了一定内存空间

linux下DHCP服务搭建

实验环境 RHEL5.9 dhcp服务器 RHEL5.9 LINUX客户端 win7    windows客户端 实验前提: 1,服务器与客户机需要在同一个网段 2,dhcp需要有固定IP 实验步骤: 服务端操作步骤: 1,设置IP cat /etc/sysconfig/network-scripts/ifcfg-eth0 DEVICE=eth0    //设备名 BOOTPROTO=static    //静态IP HWADDR=00:0C:29:DB:02:CE ONBOOT=yes  //

linux下nsf服务搭建

实验环境 RHEL5.9两台 实验一: 将/root 共享给192.168.10.20,可写.同步,允许客户机以root权限访问 服务端配置: [[email protected] ~]# rpm -qa |grep nfs  //检查软件包是否安装 nfs-utils-lib-1.0.8-7.9.el5 nfs-utils-1.0.9-66.el5 [[email protected] ~]# rpm -qa |grep portmap portmap-4.0-65.2.2.1 [[email

Linux 下Telnet 服务安装

Linux 下Telnet 服务安装 注:以下所有命令均在root用户下执行. 命令测试在Linxu版本6.x下完成,部分命令不适用Linux 7.0以上 1.简介 默认情况下Linux只安装了Telnet客户端,而没有安装服务端 [[email protected] ~]# rpm -qa | grep telnet telnet-0.17-48.el6.x86_64 2.安装Telnet 服务端 2.1在配置有yum情况下 yum install -y telnet* 2.2 在未配置yum

DHCP服务介绍及Linux下DHCP服务的管理配置

1. DHCP服务简介 DHCP是Dynamic Host Configuration Protocol,动态主机配置协议,是用来在物理网络给主机分配ip地址的一种方式,区别于bootp,一次分配终身使用的缺点. DHCP提出的租约的概念,使得可以根据需要动态确定主机需要的IP地址,并且IP地址可以循环使用. 2. DHCP结构 DHCP是典型的C/S结构,需要服务端启动守护进程来保证来自client段的请求能被响应,DHCP的工作原理如下: 可以通过DORA来记忆: Client: DHCP

TCP协议下的服务端并发,GIL全局解释器锁,死锁,信号量,event事件,线程q

TCP协议下的服务端并发,GIL全局解释器锁,死锁,信号量,event事件,线程q 一.TCP协议下的服务端并发 ''' 将不同的功能尽量拆分成不同的函数,拆分出来的功能可以被多个地方使用 TCP服务端实现并发 1.将连接循环和通信循环拆分成不同的函数 2.将通信循环做成多线程 ''' # 服务端 import socket from threading import Thread ''' 服务端 要有固定的IP和PORT 24小时不间断提供服务 能够支持并发 ''' server = sock