本文将会简单介绍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循环中,然后每一次接收到了连接,则创建一个子进程,然后子进程去执行读写操作,而父进程则继续监听。代码如下:

 #include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h> #include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h> int main(void)
{
int sockfd;
// 创建一个Socket
sockfd = socket(AF_INET,SOCK_STREAM,);
if(sockfd == -){
perror("error");
exit();
} ///////////////////////////////////////////////////////////
// struct sockaddr addr; // 这是一个通用结构,一般是用具体到,然后转型
struct sockaddr_in sockdata;
sockdata.sin_family = AF_INET;
sockdata.sin_port = htons();
sockdata.sin_addr.s_addr = inet_addr(我是IP字符串); int optval = ;
if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval)) == -)
{
perror("error");
exit();
}
if(bind(sockfd,(struct sockaddr *)&sockdata,sizeof(sockdata)) < ){
perror("error");
exit();
} ////////////////////////////////////////////////////////////
if(listen(sockfd,) == -){
perror("error");
exit();
} //////////////////////////////////////////////////////////
struct sockaddr_in peeradr;
socklen_t peerlen = sizeof(peeradr); // 得有初始值 /////////////////////////////////////////////////////////
char recvBuff[]={};
int conn = ;
while(){
conn = accept(sockfd,(struct sockaddr *)&peeradr,&peerlen);
if(conn == -){
perror("error");
exit();
}
// 每来一个链接fork一个进程。
pid_t pid;
pid = fork(); if(pid == ){
int ret = ;
close (sockfd); // 由于子进程复制来sockfd,所以关掉它。 不干涉父进程来,因为这是一个副本。由父进程继续监听
printf("收到的IP %s\n 客户端端口是:%d\n",inet_ntoa(peeradr.sin_addr),ntohs(peeradr.sin_port));
while((ret = read(conn,recvBuff,sizeof(recvBuff))) && ret > ){
// 服务器收到打印数据,然后回发
fputs(recvBuff,stdout);
write(conn,recvBuff,ret);
}
exit();
}
else if(pid > ){
close(conn); // 父进程只管监听,不需要链接套接字!!
}
else{
perror("error");
close(conn);
close(sockfd);
exit();
}
}
close(conn);
close(sockfd);
return ;
}

server.c

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

 #include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h> #include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h> int main(void)
{
int sockfd;
// 创建一个Socket
sockfd = socket(AF_INET,SOCK_STREAM,);
if(sockfd == -){
perror("error");
exit();
} ///////////////////////////////////////////////////////////
// struct sockaddr addr; // 这是一个通用结构,一般是用具体到,然后转型
struct sockaddr_in sockdata;
sockdata.sin_family = AF_INET;
sockdata.sin_port = htons();
sockdata.sin_addr.s_addr = inet_addr("我是IP字符串");
if(connect(sockfd,(struct sockaddr *)&sockdata,sizeof(sockdata)) == -){
perror("error");
exit();
} char sendBuff[] = {};
char recvBuff[] = {}; while(fgets(sendBuff,sizeof(sendBuff),stdin) != NULL){
// 将输入到数据送到服务端
write(sockfd,sendBuff,sizeof(sendBuff));
// 从服务器读数据
read(sockfd,recvBuff,sizeof(recvBuff)); // 显示在屏幕上
fputs(recvBuff,stdout);
// 清零
memset(recvBuff,,sizeof(recvBuff));
memset(sendBuff,,sizeof(sendBuff));
} close(sockfd);
return ;
}

client.c

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

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

    一.Linux发送网络消息的过程 (1) 应用程序调用write()将消息发送到内核中 ( 2)内核中的缓存达到了固定长度数据后,一般是SO_SNDBUF,将发送到TCP协议层 (3)IP层从TCP层 ...

  2. 7、Web Service-IDEA-jaxws规范下的 服务端/客户端 开发

    前提简介:这里之后即使基于IDEA进行开发的,风格与之前有些不同之处! 1.服务端的开发 1.创建新的项目 2.pom.xml 添加开发时所需要的依赖 <?xml version="1 ...

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

    解决了 windows下用root登录linuxsamba后有部分目录访问无权限的问题.应该是SELinux 设置问题. 对selinux进行修改,一般为终止这项服务,操作如下: 查看SELinux状 ...

  4. c++ 网络编程(一)TCP/UDP windows/linux 下入门级socket通信 客户端与服务端交互代码

    原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/9601511.html c++ 网络编程(一)TCP/UDP  入门级客户端与服务端交互代码 网 ...

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

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/9613861.html 好了,继上一篇说到多进程服务端也是有缺点的,每创建一个进程就代表大量的运 ...

  6. CentOS7下rsync服务端与Windows下cwRsync客户端实现数据同步配置方法

    最近需求想定期备份服务器d盘的数据到Linux服务器上面,做个笔记顺便写下遇到的问题 以前整过一个win下的cwrsync(客户端)+rsync(服务端:存储)的bat脚本 和整过一个Linux下的r ...

  7. TCP/IP网络编程之多进程服务端(二)

    信号处理 本章接上一章TCP/IP网络编程之多进程服务端(一),在上一章中,我们介绍了进程的创建和销毁,以及如何销毁僵尸进程.前面我们讲过,waitpid是非阻塞等待子进程销毁的函数,但有一个不好的缺 ...

  8. Linux 下Telnet 服务安装

    Linux 下Telnet 服务安装 注:以下所有命令均在root用户下执行. 命令测试在Linxu版本6.x下完成,部分命令不适用Linux 7.0以上 1.简介 默认情况下Linux只安装了Tel ...

  9. TCP/IP网络编程之基于UDP的服务端/客户端

    理解UDP 在之前学习TCP的过程中,我们还了解了TCP/IP协议栈.在四层TCP/IP模型中,传输层分为TCP和UDP这两种.数据交换过程可以分为通过TCP套接字完成的TCP方式和通过UDP套接字完 ...

随机推荐

  1. C#冒泡算法复习

    C#冒泡算法复习 冒泡算法的意思:每一趟找到一个最小或最大的数放到最后面,比较总数的n-1次(因为比较是2个双双比较的) 第一层循环表示进行比较的次数,总共要比较(数的)-1次 (因为比较是2个双双比 ...

  2. Java基本数据类型总结二

    Java 基本数据类型总结二 变量就是申请内存来存储值.也就是说,当创建变量的时候,需要在内存中申请空间. 内存管理系统根据变量的类型为变量分配存储空间,分配的空间只能用来储存该类型数据. 因此,通过 ...

  3. Eclipse 菜单---Eclipse教程第04课

    Eclipse 查看的菜单栏通常包含以下几个菜单: File 菜单 Edit 菜单 Navigate 菜单 Search 菜单 Project 菜单 Run 菜单 Window 菜单 Help 菜单 ...

  4. PaaS服务之路漫谈(一)

    此文已由作者尧飘海授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. PaaS服务之路漫谈(一) 1983年,SUN公司提出的网络即计算的理念:2006年亚马逊(Amazon)推 ...

  5. 从事IT业一个8年老兵转行前的自我总结2——从《易经》说开来

    近些年一直在读<易经>,收获颇多.以前看不贯的人或物现在可以淡然看定,以前看不开的一些事现在也安然放下,以前看不透的某些事现在也都可看透八九不离十. 古人云:不读<易>不可为将 ...

  6. Pascal小游戏之奇葩的RPG

    Pascal吧友作品 一个小RPG Chaobs转载 varplife,plifemax,patt,pre:integer;gr,ex,exmax:integer;alife,alife1,aatt, ...

  7. Hyper-V 安装Windows 2008,08 R2,12 R2 无网卡驱动的解决办法

    最近玩 Hyper -V ,都是在网上找的资料进行操作的.后面发觉园友提供的一些操作 按部就班的做下来,别人 可以 ,我的就是不行. 最近就遇到一个很烦闷的事情.(如题) 安装好系统之后 发现 没有网 ...

  8. Python 快速部署安装所需模块

    需求 我们需要在拷给别人或者提交至服务器也用同样的模块,好保持和开发的一样,所以我们需要自己手动写配置模块信息. 方法 在根目录下创建一个 requirements.txt  文件 里面写 模块名== ...

  9. Oracle 监听/数据库 启动/关闭

    LSNRCTL命令启动.关闭和查看监听器的状态的方法 从lsnrctl status命令的输出中得到监听器状态,包括如下的信息: 监听器的启动时间 监听器的运行时间 监听器参数文件listener.o ...

  10. Linux再谈互斥锁与条件变量

    原文地址:http://blog.chinaunix.net/uid-27164517-id-3282242.html pthread_cond_wait总和一个互斥锁结合使用.在调用pthread_ ...