服务器测试效果:

andrew@andrew-Thurley:~/work/network$ bin/echo_tcp_server 8888
client: 127.0.0.1(55610) connected
start read and write!
name
start read and write!
name
start read and write!

客户端测试效果:

andrew@andrew-Thurley:~/work/network$ bin/echo_tcp_server 8888
client: 127.0.0.1(55610) connected
start read and write!
name
start read and write!
name
start read and write!

创建的过程就是服务器接到连接请求就会创建一个进程来与该客户端仅进行交互:

整个工程中使用到的文件树形图如下所示:

andrew@andrew-Thurley:~/work$ tree network
network
├── bin
│   ├── echo_tcp_client
│   ├── echo_tcp_server
│
│
├── include
│   └── msg.h
├── Makefile
├── obj
│   └── msg.o
├── src├── echo_tcp_client.c├── echo_tcp_server.c├── msg.c

echo_tcp_server.c文件

#include <netdb.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <signal.h>
#include <time.h>
#include "msg.h"
#include <sys/signal.h>
#include <errno.h>
#include <sys/types.h>
#include <wait.h>
#include <arpa/inet.h>/**************************************使用多进程处理并发***************************************/
//处理多个进程连接
//测试方法,运行程序,并指定端口号8888
//在另一个终端上使用
// telnet 127.0.0.1 8888进行连接
//127.0.0.1是没有连接网络时使用的本地回环ip地址/*声明自定义函数*/
void sig_handler(int signo);
void out_addr(struct sockaddr_in *clientaddr);
void do_service(int fd);
int sockfd;int main(int argc, char * argv[])
{if(argc < 2){printf("usage: %s #port\n",argv[0]);exit(1);}if(signal(SIGINT, sig_handler) == SIG_ERR)   //开始捕捉信号  SIGINT{perror("signal sigint error!");exit(1);}/*步骤1创建socket*AF_INET IPV4*SOCK_STREAM 采用tcp协议*0 采用上面设置的协议类型*/sockfd = socket(AF_INET, SOCK_STREAM, 0);  //使用默认协议if(sockfd < 0){perror("socket error!");exit(1);}/**步骤2,:调用bind函数将socket和地址(包括 IP,port)进行绑定**/struct sockaddr_in serveraddr;  //声明专用地址,需要的时候再转换为通用地址memset(&serveraddr, 0, sizeof(serveraddr));//往地址填入ip、port、intnernet地址族类型serveraddr.sin_family = AF_INET; //IPV4serveraddr.sin_port = htons(atoi(argv[1]));  //填入端口 serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);if(bind(sockfd, (struct sockaddr *) &serveraddr,sizeof(serveraddr)) < 0){perror("bind error!");exit(1);}/* *步骤3:调用listen函数启动端口监听*通知系统去接受来自客户端的连接请求*listen 的第二个参数10是请求队列长度,将接收到的客户端连接请求放到对应的队列当中*/if(listen(sockfd, 10) < 0)  //10监听的队列的上限{perror("listen error!");exit(1);}/**步骤4:调用accept函数,从队列中获得*      一个客户端请求连接,并返回新的sock文件描述符fd,*      因为listen能够监听好多的连接请求,*      使用accept获得一个连接使用*      若是accept没有获得客户端连接,会进行阻塞,直到获得客户端连接*/struct sockaddr_in clientaddr;socklen_t clientaddr_len = sizeof(clientaddr);while(1){//使用循环就能够在断开与一个客户端连接之后,在连接下一个客户端连接int fd = accept(sockfd, (struct sockaddr*) &clientaddr,&clientaddr_len);if(fd < 0){perror("accept error!");continue;}/**步骤5: 启动子进程调用IO函数(read/write)和连接的客户端进行双向通信*/pid_t pid = fork();if(pid < 0){continue;}else if(pid == 0)  //子进程{//子进程会从父进程中继承相应的文件描述符,指向同一个文件out_addr(&clientaddr);do_service(fd);/*步骤6:关闭套接字描述符*/close(fd);printf("child p is close\n");break;  //子进程跳出循环后直接 return//  exit(0);}else{//父进程/*步骤6:关闭套接字描述符*/close(fd);}}return 0;
}void sig_handler(int signo)
{if(signo == SIGINT){printf("server close\n");/*步骤6:关闭socket*/close(sockfd);exit(1);}if(signo  == SIGCHLD){printf("child process deaded...\n");wait(NULL);  //会自动回收子进程  wait函数中填入0说明对于回收的子进程不关心只是去回收子进程}}void out_addr(struct sockaddr_in *clientaddr)
{/*将端口网络字节序转换为主机字节序 */   /*port是short类型数据*/int port = ntohs(clientaddr->sin_port);char ip[16];memset(ip, 0, sizeof(ip));/*将ip地址从网络地址转换为点分十进制*//*需要注意的地方#include <arpa/inet.h>const char *inet_ntop(int af, const void *src,char *dst, socklen_t size);在函数中 const void *src说明第二个参数是指针类型的数据,但是当传入clientaddr->sin_addr == (*clientaddr).sin_addr.s_addr就不在是一个指针类型数据因此需要使用&将其取址之后在传入。*/inet_ntop(AF_INET, &clientaddr->sin_addr, ip, sizeof(ip));printf("client: %s(%d) connected\n",ip, port);
}void do_service(int fd)
{/*和客户端双向通讯,进行读写操作*/char buff[512];while(1){memset(buff, 0, sizeof(buff));printf("start read and write!\n");size_t size;if((size = read_msg(fd, buff, sizeof(buff))) < 0){perror("protocal error!");break;}else if (size == 0){break;}else{printf("%s\n", buff);if(write_msg(fd, buff, sizeof(buff)) < 0){if(errno == EPIPE)//若是对方已经关闭就直接跳出{perror("write_msg error!");break;}}}}
}

echo_tcp_client.c文件:

#include <netdb.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <signal.h>
#include <time.h>
#include "msg.h"
#include <sys/signal.h>
#include <errno.h>
#include <sys/types.h>
#include <wait.h>
#include <arpa/inet.h>int main(int argc, char * argv[])
{if(argc < 3){printf("usage:%s ip port\n",argv[0]);exit(1);}/*步骤1:创建socket*/int sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd < 0){perror("socket error!");exit(1);}/*往serveraddr中填入ip,port和地址族类型(ipv4)*/struct sockaddr_in serveraddr;memset(&serveraddr, 0, sizeof(serveraddr));serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(atoi(argv[2]));/*将字符串ip地址转换为网络字节序填入 serveraddr中*/inet_pton(AF_INET, argv[1], &serveraddr.sin_addr.s_addr);/**步骤2: 客户端调用connect函数连接到服务器端*/if(connect(sockfd, (struct sockaddr *)&serveraddr,sizeof(serveraddr)) < 0){perror("connect error!");exit(1);}/*步骤3:调用IO函数,read和write和服务器进行双向通信*/char buff[512];size_t size;char *prompt = ">";while(1){memset(buff, 0, sizeof(buff));write(STDOUT_FILENO, prompt, 1);size = read(STDIN_FILENO, buff, sizeof(buff));if(size < 0) continue;buff[size - 1] = '\0'; if(write_msg(sockfd, buff, sizeof(buff)) < 0){perror("write error!");continue;   //就算写出错也结合运行  进行下次的发送}else {//客户端发送成功if(read_msg(sockfd, buff, sizeof(buff)) < 0){perror("read msg error!");continue;}else{printf("%s\n",buff);}}}/*步骤4:关闭socket套接字*/close(sockfd);return 0;
}

msg.c文件:

#include "msg.h"
#include <stdio.h>
#include <unistd.h>
#include <error.h>
#include <memory.h>
#include <sys/types.h>/*使用自定义协议进行数据传输*/static unsigned char msg_check(Msg *message);/*
*发送一个基于自定义协议的message
*发送的数据存放在buff中
*/
extern int write_msg(int sockfd,char *buff, size_t len)
{Msg message;memset(&message, 0, sizeof(message));strcpy(message.head, "iotek2012");memcpy(message.buff, buff, len);message.checknum = msg_check(&message);if(write(sockfd, &message, sizeof(message)) != sizeof(message)){return -1;} }/*
*读取一个基于自定义协议的message,
*读取的数据存放在buff中
*/
extern int read_msg(int sockfd, char *buff, size_t len)
{Msg message;memset(&message, 0, sizeof(message));size_t size;if((size = read(sockfd, &message, sizeof(message))) < 0){return -1;}else if(size == 0){return 0;}unsigned char s = msg_check(&message);if((s == (unsigned char)message.checknum) && (!strcmp("iotek2012", message.head))){strcpy(buff,message.buff);return sizeof(message);}return -1;
}static unsigned char msg_check(Msg *message)
{unsigned char s = 0;int i;for(i = 0; i < sizeof(message->head); i ++){s += message->head[i];}for(i = 0; i < sizeof(message->buff); i ++){s += message->buff[i];}return s;
}

msg.h文件:

#ifndef __MSH_H
#define __MSG_H
#include <stdio.h>
#include <unistd.h>
#include <error.h>typedef struct{//协议头部char head[10];char checknum; //校验码//协议体部char buff[512];  //数据
}Msg;/*
*发送一个基于自定义协议的message
*发送的数据存放在buff中
*/
extern int write_msg(int sockfd,char *buff, size_t len);/*
*读取一个基于自定义协议的message,
*读取的数据存放在buff中
*/
extern int read_msg(int sockfd, char *buff, size_t len);#endif

Makefile文件:

为了使思路清晰,在编写Makefile文件的时候,没有使用任何$<,$@,$^等自动化变量

.PHONY : all
.PHONY : cleanall :bin/echo_tcp_server bin/echo_tcp_clientbin/echo_tcp_server : echo_tcp_servermv echo_tcp_server bin/echo_tcp_serverbin/echo_tcp_client : echo_tcp_clientmv echo_tcp_client bin/echo_tcp_clientecho_tcp_server : src/echo_tcp_server.c obj/msg.ogcc -o echo_tcp_server -Iinclude src/echo_tcp_server.c obj/msg.oecho_tcp_client : src/echo_tcp_client.c obj/msg.ogcc -o echo_tcp_client -Iinclude src/echo_tcp_client.c obj/msg.oobj/msg.o : msg.omv msg.o obj/msg.omsg.o : src/msg.c  include/msg.hgcc -c -Iinclude src/msg.c

socket使用多进程实现并发的服务器相关推荐

  1. 128-网络编程:TCP通信的并发(多进程实现并发服务器)

    3.TCP通信的并发(多进程实现并发服务器) 3.1 多进程实现并发服务器 要实现TCP通信服务器处理并发任务,使用多线程或者多进程来解决. 思路:1. 一个父进程,多个子进程2. 父进程负责等待并接 ...

  2. 第4章 Linux网络编程 22.多进程实现并发服务器、多线程实现并发服务器

    目录 多线程实现并发服务器 多进程实现并发服务器 多线程实现并发服务器 server_thread.c #include <stdio.h> #include <arpa/inet. ...

  3. 【Linux网络编程部分----多进程高并发poll模型】

    目录 前言 背景 分析 编写步骤 服务器: 客户端: 服务器端代码 附:文件操作部分 附:目录操作部分 客户端代码 全部代码 头文件部分 服务器全部代码 客户端所有代码 总结: 前言 本文采用  Vi ...

  4. linux线程池实现多线程并发,基于Linux的多线程池并发Web服务器设计-电子设计工程.PDF...

    基于Linux的多线程池并发Web服务器设计-电子设计工程.PDF 第 卷 第 期 电子设计工程 年 月 基于 的多线程池并发 服务器设计 陈 涛 任海兰 武汉邮电科学研究院 湖北 武汉 摘要 时至今 ...

  5. php多进程并发,php多进程模拟并发事务

    用实例代码给大家介绍关于php多进程模拟并发事务产生的一些问题,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧 数据表 drop table if exists `test`; cre ...

  6. 100万并发连接服务器

    100万并发连接服务器笔记之准备篇 前言 测试一个非常简单服务器如何达到100万(1M=1024K连接)的并发连接,并且这些连接一旦连接上服务器,就不会断开,一直连着.  环境受限,没有服务器,刚开始 ...

  7. 高并发WEB服务器设计

    目标:考虑设计一个高并发WEB服务器框架,有哪些惯用的手法?希望在本篇文章给出一个标准答案. 关键词: 迭代模型,并发模型,I/O多路复用,线程池,协程 参考:Apache/MySQL,Nginx, ...

  8. C++socket网络编程大全实战http服务器(支持php)视频课程-夏曹俊-专题视频课程

    C++socket网络编程大全实战http服务器(支持php)视频课程-16782人已学习 课程介绍         C++socket网络编程大全实战http服务器(支持php)视频培训教程概况:本 ...

  9. 使用Socket及ServerSocket创建简单的服务器

    使用Socket及ServerSocket创建简单的服务器 @(JAVA)[java] 参考自core java package com.lujinhong.corejava;import java. ...

最新文章

  1. s5pv210 音频播放问题 MPlayer移植
  2. symfony学习笔记——路由
  3. ClassLoader简介
  4. JavaFX图表(一)
  5. 前端学习(2665):完成vue3.0的todolist添加
  6. 生活:小孩的世界很简单
  7. 构建嵌入式版本的 ACE TAO 6.5.3
  8. ROS入门 常用工具
  9. 3-unit8 Mariadb数据库
  10. Mysql 2018国家统计局区划和城乡划分数据库(包含经纬度数据,以及数据来源,提供大家参考)
  11. VMware Horizon 8安装部署(八)访问测试,成功部署。
  12. php+dns+缓存,清理电脑dns缓存方法
  13. 自学软件测试需要多久?能掌握吗?
  14. 阿里云对象存储OSS存储照片
  15. 阿里云短信api 回执 回复
  16. 惠州环境监测实验室建设面积要求
  17. 【转贴】百度贴吧成就一段姻缘!一句被五重密码保护的表白破译全记录
  18. Java、JSP就业信息管理系统的设计与实现
  19. 通过指定的URL获取返回图片的BASE64编码
  20. fatal error C1083: 无法打开预编译头文件 的解决方法

热门文章

  1. Create Tables and Build inserts from Tables by using Mygeneration Templates(Sql Server)
  2. nyoj 208 Supermarket(贪心)
  3. hdu 2874(LCA + 节点间距离)
  4. 图像分割综述【深度学习方法】
  5. Open3D编译安装
  6. Create a PCL visualizer in Qt with QtDesigner
  7. NYOJ 683 Jim的实验
  8. oracle 自定义函数
  9. Django与CSRF 、AJAX
  10. DIB位图(Bitmap)的读取和保存