Linux:服务器/客户端API调用错误检查
昨天和今天上午,我分别实现简单的服务器和客户端,运行之后表示没问题,一切正常。但是这还是有问题的,最大的一个就是没有错误检查。现在我们来加上错误检查:
服务器的代码:
|
#include #include #include #include #include #include #include
#define
int main(void) { int sfd; //服务器的socket文件描述符 int cfd; //客户端的socket文件描述符 struct struct socklen_t clie_len; //客户端的地址结构的大小 char buf[BUFSIZ]; //用于储存客户端发来的信息
//第一个参数是指定IPV4协议族,第二个参数是指定TCP协议,第三个参数是使用默认的协议,一般都是用0 if (-1 == (sfd = socket(AF_INET, SOCK_STREAM, 0)))//创建服务器的socket文件 { perror("socket error"); exit(1); }
//赋值服务器地址结构体 serv_addr.sin_family = AF_INET; //选择协议族位IPV4 serv_addr.sin_port = htons(SERV_PORT); //监听本地所有的IP地址;INADDR_ANY表示的是一个服务器上所有的网卡(服务器可能不止一个网卡)多个本地ip地址都进行绑定端口号,进行侦听。 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); //绑定我们自定义的端口号9527
//第一个参数是服务器的socket文件描述符,第二个参数要强转为sockaddr,原因后面会说;第三个参数是服务器地址结构体的大小 if (-1 == (bind(sfd, (struct { perror("bind error"); exit(1); } //服务器能够同时接受多少个客户端连接,默认128. if (-1 == (listen(sfd, 32))) { perror("listen error"); exit(1); }
//确定客户端地址结构大小,用于accept函数使用 clie_len = sizeof(clie_addr);
//连接客户端,返回一个新的socket文件描述符。第一个参数时服务器socket文件描述符,第二个时客户端地址结构体,这里也要强转,第三个是客户端地址的大小,注意的是:第二个是传出参数,第三个 是传入传出参数 if (-1 == (cfd = accept(sfd, (struct { perror("accept error"); exit(1); }
while (1) { int n = read(cfd, buf, sizeof(buf));//从客户端读 for (int i = 0; i < n; i++) buf[i] = toupper(buf[i]); write(cfd, buf, n);//写到客户端 } //关闭文件描述符 close(sfd); close(cfd); } |
客户端的代码:
|
#include #include #include #include #include #include #include #include #include #define int main(void) { int c_fd; int len; char buf[BUFSIZ]; struct socklen_t addr_len;
if ((c_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket error"); exit(1); }
if (-1 == (inet_pton(AF_INET, "127.0.0.1", &clie_addr.sin_addr.s_addr))) { perror("inet_pton error"); exit(1); } clie_addr.sin_family = AF_INET; clie_addr.sin_port = htons(ADDR_POST);
if (-1 == (connect(c_fd, (struct { perror("connect error"); exit(1); }
while (1) { fgets(buf, sizeof(buf), stdin); write(c_fd, buf, strlen(buf)); len = read(c_fd, buf, sizeof(buf)); write(STDOUT_FILENO, buf, len); } close(c_fd);
return 0; } |
哇,好累的啊。这样检查效率好低,并且严重的扰乱了代码逻辑,并且还没检查完所有的函数,不行,得换方法了。
方法就是:封装!
我们自己实现一个同名函数(首字母大小),在新函数中调用原来的系统函数。并且做错误处理。头文件:my_error.h
|
#ifndef __WRAP_H_ #define void perr_exit(const int Accept(int int Bind(int int Connect(int int Listen(int int Socket(int ssize_t Read(int ssize_t Write(int int Close(int ssize_t Readn(int ssize_t Writen(int ssize_t my_read(int ssize_t Readline(int #endif |
然后是实现:my_error.c
|
#include #include #include #include #include #include #include #include #include #include void perr_exit(const { perror(s); exit(1); } int Accept(int { int n; again: //accrpt是慢速系统调用,在阻塞期间可能会被信号杀死 if ((n = accept(fd, sa, salenptr)) < 0) { if ((errno == ECONNABORTED) || (errno == EINTR))//进一步判断返回值,EINTR代表函数被信号中断;ECONNABORTED代表连接中断,这两种情况不算是异常,所以重启 goto again; else perr_exit("accept error"); } return n; } int Bind(int { int n; if ((n = bind(fd, sa, salen)) < 0) perr_exit("bind error"); return n; } int Connect(int { int n; if ((n = connect(fd, sa, salen)) < 0) perr_exit("connect error"); return n; } int Listen(int { int n; if ((n = listen(fd, backlog)) < 0) perr_exit("listen error"); return n; } int Socket(int { int n; if ((n = socket(family, type, protocol)) < 0) perr_exit("socket error"); return n; } ssize_t Read(int { ssize_t n; again: //read也是慢速系统调用。 if ((n = read(fd, ptr, nbytes)) == -1) { if (errno == EINTR) goto again; else return -1; } return n; } ssize_t Write(int { ssize_t n; again: if ((n = write(fd, ptr, nbytes)) == -1) { if (errno == EINTR) goto again; else return -1; } return n; } int Close(int { int n; if ((n = close(fd)) == -1) perr_exit("close error"); return n; }
/* 应用场景:以太网帧一次最多发送1500字节的数据,若是我们要读取4096字节的数据,但是4096字节的数据需要四次才能完全发送过来,如果只调用一次read,那就只能读到1500就返回不读了,所以我们需要让系统调用多次,必须读够那么多数据。所以这次调用,n要等于4096
//参数三:应该读取到的字节数*/ ssize_t Readn(int { size_t nleft; //unsigned int 剩余未读取的字节数 ssize_t nread; //int 实际读取到的字节数 char *ptr;
ptr = (char*)vptr; nleft = n; //n 未读取到的字节数
while (nleft > 0) { if ((nread = read(fd, ptr, nleft)) < 0) { if (errno == EINTR)// EINTR(表"被信号中断") nread = 0; // 读到了0个字节 else return -1;//其他错误 } else break; nleft -= nread; ptr += nread; } return }
ssize_t Writen(int { size_t nleft; //剩余未写的字节数 ssize_t nwritten; //实际写的字节数 const
ptr = (char*)vptr; nleft = n; //未写的字节数
while (nleft > 0) { if ((nwritten = write(fd, ptr, nleft)) <= 0) { if (nwritten < 0 && errno == EINTR) nwritten = 0; else return -1; } nleft -= nwritten; ptr += nwritten; } return }
static { static static static
if (read_cnt <= 0) { again: if ((read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) { if (errno == EINTR) goto again; return -1; } else return 0; read_ptr = read_buf; } read_cnt--; *ptr = *read_ptr++; return 1; } /* 应用场景:fgets只能从普通文件或者标准输入输出设备读去数据,他不能从socket中读取数据,所以用readline代替fgets来读取一行 */ ssize_t Readline(int { ssize_t n, rc; char c, *ptr; ptr = (char*)vptr;
for (n = 1; n < maxlen; n++) { if ((rc = my_read(fd, &c)) == 1) { *ptr++ = c; if (c == '\n') break; } else *ptr = 0; return n - 1; } else return -1; } *ptr = 0; return n;//返回读到的字节数 } |
在这里面。尤其要引起重视的是最后四个函数。在以后的开发中是很有可能用到的。
Linux:服务器/客户端API调用错误检查的更多相关文章
- 通过 Jersey Http请求头,Http响应头,客户端 API 调用 REST 风格的 Web 服务
原地址:http://blog.csdn.net/li575098618/article/details/47853263 Jersey 1.0 是一个开源的.可以用于生产环境的 JAX-RS(RES ...
- Jersey客户端API调用REST风格的Web服务
Jersey 客户端 API 基础 jersey-1.14.jar 密码: cxug 要开始使用 Jersey 客户端 API,你首先需要创建一个 com.sun.jersey .api.client ...
- This server is in the failed servers list: localhost/127.0.0.1:16000 启动hbase api调用错误
api 调用发现错误 Mon Nov 18 23:04:31 CST 2019, RpcRetryingCaller{globalStartTime=1574089469858, pause=100, ...
- JAVA客户端API调用memcached两种方式
1. memcached client for java客户端API:memcached client for java 引入jar包:java-memcached-2.6.2.jar package ...
- 通过Jersey客户端API调用REST风格的Web服务
Jersey 客户端 API 基础 要开始使用 Jersey 客户端 API,你首先需要创建一个 com.sun.jersey .api.client.Client 类的实例.下面是最简单的方法: i ...
- linux服务器部署svn常见错误处理→转载
转载地址→http://blog.seweal.com/post/2013-02-04/svn-errors [开放svn端口] iptables -I INPUT -p tcp --dport 36 ...
- Zookeeper 客户端API调用示例(基本使用,增删改查znode数据,监听znode,其它案例,其它网络参考资料)
9.1 基本使用 org.apache.zookeeper.Zookeeper是客户端入口主类,负责建立与server的会话 它提供以下几类主要方法 : 功能 描述 create 在本地目录树中创建 ...
- linux 服务器/客户端 tcp通信的简单例子
昨天弄了sublime之后没有弄输入中文的了,学生党来着,刚好可以练练英语(英语渣渣,还要考六级),所以注释都写英文的(语法什么的就别太深究了) 服务器端: /*start from the very ...
- Linux服务器内存监控—每小时检查&超出发送邮件&重启占用最高的Java程式
简介与优点 使用该脚本能自行判断系统内存使用情况是否超出设定百分比 能在超出预警值时执行重启程式的操作 能记录重启过程,并将具体LOG邮件发送给指定收信人 可以设定Crontab排程,达成每隔一段时间 ...
随机推荐
- win7 没有权限使用网络资源
局域网下同一工作组电脑无法访问 提示"....没有权限使用网络资源...." 一.组策略 win + R 输入gpedit.msc并回车,打开本地组策略编辑器 按如下展开 计算机配 ...
- jstat 详解
最近项目里面使用到了多线程,有时候多线程会存在挂掉的情况,趁机好好学习总结一下JVM调优的方法. jstat使用: #jstat -help|-options #jstat -<option&g ...
- pthread线程特定数据
举个栗子 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/t ...
- cocos源码分析--用Sprite加载自定义着色器
本文写一个使用动态更新属性变量的自定义着色器.在这个例子中,小图标的位置根据手指的触摸而移动,以屏幕重点为参照物,屏幕中向下的部分根据手指的点击乘以一个绿色的颜色值,向上的部分乘以一个红色的颜色值. ...
- Device supprts x86,armeabi-v7a,but APK only aupports armeabi;模拟机不能运行。
在真机可以运行,模拟机却不可以: 这个是模拟机: 修改: defaultConfig { ndk{ abiFilters "armeabi" } } 为: defaultConfi ...
- html跳页面传值
从a.html跳转到b.html并且把a.html的值name传入b.html 在a.html页面,url路径后面带参数,参数与url之间用?隔开 window.location.href = &q ...
- python import问题
python中包:一个文件夹中必须要有__init__.py文件,才能被识别为 包,才能被其他模块引入python中 模块的查找顺序是:内存中已经加载的模块->内置模块->sys.path ...
- 【IP代理】国内省市域名代理
最近遇到一个测试问题,就是投放时需要按地域投放,所以需要对指定的IP地址范围内的地方投放才有效. 所以,就调查了下IP代理的方式,一个是SSR,这个好像只能代理国外的域名方式,另外一个就是百度搜索IP ...
- android 开发 singleTask启动模式下传值的坑
日常填坑. 做了什么操作引起的?如下: 在活动A 启动模式设置为singleTask ,然后再用活动A启动活动B,活动B启动活动C. 现在我的活动C要使用intent携带值去启动活动A.在活动A中正常 ...
- uva-10954-贪心
题意:俩个数相加,产生的和就是这次加法的代价,问,所有数都加起来,最小代价是多少 解题思路:贪心,每次都选取最小俩个数相加,如果只有一个数,计算完毕,注意,加法的和要再次入队列. #include & ...