2019独角兽企业重金招聘Python工程师标准>>>

调试输出函数

这里利用宏来实现debug的相关输出

int dbg_level = -1;
#define print_dbg(level, ...)                       \({                             \if (level <= dbg_level) {                  \fprintf(stderr, "%s, %u, %s: ",              \__FILE__, __LINE__, __func__);         \fprintf(stderr, ##__VA_ARGS__);                \}                              \})

基本的socket编程

前面有讲过基本的网络编程,主要是利用socket的相关函数进行实现,其大体框架如下

int sockfd = socket(PF_INET, SOCK_STREAM, 0); // 创建套接字
if(sockfd < 0)
{print_dbg(0, "create socket error\n");return;
}struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
if(bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr) < 0)
{print_dbg(0, "Failed to bind port:%d\n", port);return;
}if(listen(sockfd, SOMAXCONN) < 0)
{print_dbg(0, "Listen error\n");return;
}while(1)
{clientfd = accept(sockfd, (struct sockaddr *)&client_addr, NULL);if(clientfd < 0){if(error == EINTR) // 信号中断处理continue;else{print_dbg(0, "accept dumpt\n");break;}}int pid = fork();if(pid < 0){print_dbg(0, "create child process error\n");close(clientfd);continue;}else if(pid == 0){...exit(0);}...
}

扩充的socket编程

1.  首先是对socket的一些可能出现错误的函数进行再封装处理,比如accept可能出现多种错误,若只是简单的退出,则对服务器的安全性将有很大的挑战;这里对于最常见的信号中断处理,进行了再次封装

 clientfd = accept(sockfd, (struct sockaddr *)&client_addr, NULL);if(clientfd < 0){if(error == EINTR) // 信号中断处理continue;else{print_dbg(0, "accept dumpt\n");break;}}

从上面的代码可以看出,当错误号为EINTR时,忽略掉再次进入循环;再例如出现EPERM,防火墙问题时,也可以做出相应的提示

2. 除了accept之外,对于send,recv函数同样需要再次封装处理,以确保能正确的接收到数据和正确的发送完数据.下面给出了最常见的错误处理,特别是对于信号中断,一般都有做出要求

char client_ip[16];
int recvn(int fd, char *buf, size_t len, int flag)
{int size = recv(fd, buf, len, flag);if (size < 0){if (errno == EINTR)return recvn(fd, buf, len, flag);else{record_log("receive data from ip:%s error\n", client_ip);print_dbg(0, "receive data from ip:%s error\n", client_ip);return -errno;}}return size;
}int sendn(int fd, const char *buf, size_t len, int flag)
{int size = send(fd, buf, len, flag);if (size < 0)if (errno == EINTR)return sendn(fd, buf, len, flag);elsegoto ERROR;if(size != len)goto ERROR;return size;ERROR:record_log("send data to ip:%s error\n", client_ip);print_dbg(0, "receive data from ip:%s error\n", client_ip);return -errno;
}

信号与进程通信

如果我们考虑的服务器是只允许顺序的请求,即一个请求处理完毕之后再响应另一个请求;若当前正在处理一个client的请求时,此时接受到其他client的请求,这里可以利用信号来实现屏蔽处理。

思路:利用全局变量busy来决定在while(1)循环中是否接受客户端处理请求

当busy为1时,表示不再接受client请求;当busy为0时,表示可以接受client请求,并标记busy为1;

当与client建立连接的子进程结束后,要求将busy设置为0

故流程为:

signal(SIGCHLD, signa_handler); // 注册信号处理函数
while(1)
{clientfd = accept(...);...if(busy == 1){print_dbg(0, "socket busy\n");close(clientfd);continue;}busy = 1;int pid = fork();if(pid < 0) {}else if(pid == 0) {child_process(clientfd);exit(0); // 求捕获子进程结束信号,在处理函数中将busy复位为0}
}

这里主要简单的使用signal函数结合waitpid来实现这个要求

  1. signal函数

函数原型为:

#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

结合本博客主题,这里简单说明本函数具体使用的方式,首先是建一个信号处理函数,用于处理信号发生时所需要做的操作,具体代码如下:

int busy = 0;
static void signal_handler(int sig)
{int stat;pid_t pid;while ((pid = waitpid(-1, &stat, WNOHANG)) > 0);busy = 0;
}

waitpid 来处理子进程结束问题

函数原型,

#include<sys/types.h>
#include<sys/wait.h>
pid_t waitpid(pid_t pid,int * status,int options);

其中参数参考百科,但需要注意的是上面的代码,在信号处理函数中,下面这行是保障子进程结束不会僵死的关键

while ((pid = waitpid(-1, &stat, WNOHANG)) > 0);

参数 status 可以设成 NULL。参数 pid 为欲等待的子进程识别码,

其他数值意义如下:

pid<-1 等待进程组识别码为 pid 绝对值的任何子进程。

pid=-1 等待任何子进程,相当于 wait()。

pid=0 等待进程组识别码与目前进程相同的任何子进程。

pid>0 等待任何子进程识别码为 pid 的子进程。

参数options提供了一些额外的选项来控制waitpid,参数 option 可以为 0 或可以用"|"运算符把它们连接起来使用,比如:

ret=waitpid(-1,NULL,WNOHANG | WUNTRACED);

如果我们不想使用它们,也可以把options设为0,如:

ret=waitpid(-1,NULL,0);

WNOHANG 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若结束,则返回该子进程的ID。

WUNTRACED 若子进程进入暂停状态,则马上返回,但子进程的结束状态不予以理会。WIFSTOPPED(status)宏确定返回值是否对应与一个暂停子进程。

最后源代码可以参考:https://github.com/liuyueyi/sa/blob/master/server.c

测试

服务器首先接受一个R\T的字符,用于判断是接受数据还是发送数据

  1. 启动服务器

  2. 开启一个终端输入: nc 127.0.0.1 10033

    输入: R [换行] 其他的一些数据

  3. 再开启一个终端输入:  nc 127.0.0.1 10033

  4. 服务器提示socket busy,并关闭连接

转载于:https://my.oschina.net/u/566591/blog/313064

linux 网络编程之信号机制相关推荐

  1. Linux网络编程 | 信号 :信号函数、信号集、统一事件源 、网络编程相关信号

    文章目录 信号函数 信号集 统一事件源 网络编程相关信号 Linux 进程信号:信号的概念.生命周期.产生流程.阻塞 在半年前我写过一篇博客介绍了Linux中信号的概念以及处理流程,这次再来深入的讲一 ...

  2. Linux io模型及函数调用,Linux 网络编程的5种IO模型:信号驱动IO模型

    Linux 网络编程的5种IO模型:信号驱动IO模型 背景 这一讲我们来看 信号驱动IO 模型. 介绍 情景引入: 在信号驱动IO模型中,当用户线程发起一个IO请求操作,会给对应的socket注册一个 ...

  3. Linux网络编程--进程间通信(一)

    进程间通信简介(摘自<Linux网络编程>p85) AT&T 在 UNIX System V 中引入了几种新的进程通讯方式,即消息队列( MessageQueues),信号量( s ...

  4. linux系统发送信号的系统调用是,linux系统编程之信号:信号发送函数sigqueue和信号安装函数sigaction...

    信号发送函数sigqueue和信号安装函数sigaction sigaction函数用于改变进程接收到特定信号后的行为. sigqueue()是比较新的发送信号系统调用,主要是针对实时信号提出的(当然 ...

  5. Linux网络编程——黑马程序员笔记

    01P-复习-Linux网络编程 02P-信号量生产者复习 03P-协议 协议: 一组规则. 04P-7层模型和4层模型及代表协议 分层模型结构: OSI七层模型: 物.数.网.传.会.表.应TCP/ ...

  6. 150集Linux网络编程培训视频吐血整理 | 网络基础

    学习视频来源:<黑马程序员 - Linux网络编程> 协议的概念 什么是协议 从应用的角度出发,协议可理解为"规则",是数据传输和数据的解释的规则. 假设,A.B双方欲 ...

  7. Linux网络编程——千峰物联网笔记

    B站视频:千峰物联网学科linux网络编程 网址:https://www.bilibili.com/video/BV1RJ411B761?p=1 目录 第一章:计算机网络概述 1.1计算机网络发展简史 ...

  8. 计算机网络(二)Linux网络编程

    layout: post title: 计算机网络(二)Linux网络编程 description: 计算机网络(二)Linux网络编程 tag: 计算机网络 文章目录 资源共享 Linux高性能服务 ...

  9. linux网络编程大杂烩==Linux应用编程7

    一.Linux 网络编程框架 1.网络是分层的 (1)OSI 七层模型:应用层.表示层.会话层.传输层.网络层.数据链路层.物理层. (2)网络为什么要分层:互联网及其复杂,需要分层以便更好地实现网络 ...

最新文章

  1. 无意间发现的一个留学mba的论坛
  2. zabbix监控之nginx状态监控(一)
  3. python的pandas库内的函数_python 中NumPy和Pandas工具包中的函数使用笔记(方便自己查找)...
  4. duck typing java_编程语言中的鸭子类型 Duck Typing
  5. 快速找到SAP CRM WebClient UI thtmlbUtil的定义位置
  6. 社工库网址与制作方法
  7. python群发邮件1000人-python读取excel群发邮件(一)
  8. 机器学习面试之偏差方差
  9. mysql扩展中如何处理结果集_请写出PHP处理结果集的5个函数(使用mysql扩展)_学小易找答案...
  10. git 常用指令 -
  11. 从可视化模板,到数据仓库、数字化的资料,我整理并分享出来
  12. PLSQL 连接不上
  13. HDU 2063 过山车
  14. 阶段3 3.SpringMVC·_02.参数绑定及自定义类型转换_6 自定义类型转换器代码编写
  15. MyEclipse使用阿里p3c代码规范
  16. itext生成pdf间距_[itext]Java生成PDF文件
  17. 激光视觉惯导融合的slam系统
  18. 递归求地铁两站间最短路径
  19. BUUCTF 每天10道Misc Day4
  20. linux的./configure --prefix的作用

热门文章

  1. 我为 VS Code 开发了一个 Deno 插件
  2. SHOI2008仙人掌图(tarjan+dp)
  3. 《WCF技术内幕》翻译2:《WCF技术内幕》绪论
  4. Android开发之dp转像素,像素转换为dp工具类,详细代码,带有源文件下载地址。...
  5. Eclipse中SVN的安装步骤(两种)和使用方法[转载]
  6. virt-manager管理kvm
  7. 肏蛋的Loadrunner脚本
  8. redmine升级了 ,6与18日同时发布2.0.3和1.4.4
  9. 改进C#代码之24:通过定义并实现接口替代继承
  10. PowerTip of the Day-Add Help to Your Functions