linux网络编程学习笔记之二 -----错误异常处理和各种碎碎(更新中)

errno

在unix系统中对大部分系统调用非正常返回时,通常返回值为-1。并设置全局变量errno(errno.h),如socket(), bind(), accept(), listen()。

erron存放一个正整数来保存上次出错的错误值。

对线程而言。每一个线程都有专用的errno变量。不必考虑同步问题。

strerror converts to English (Note: use strerror_r for thread safety)

perror is simplified strerror/fprintf


慢系统调用

指可能永远堵塞而无法返回的系统调用,一般是一些读写的样例,如pipe。终端设备。网络连接,典型的accept(), read(), write(), open(),select(),epoll()等。

适用于慢系统调用的基本规则是:当堵塞于某个慢系统调用的进程捕获到某个信号且对应的信号处理函数返回时,系统调用可能会返回一个EINTR错误,即将errno的值置为该值。

尽管有些内核会对该系统调用重新启动,但从可移植性的角度说,对EINTR处理是必须的。

注意对connect()不能如此处理。(UNP 5.9)


一个信号被信号处理函数响应,在处理过程中,该信号被屏蔽。标准的信号实现没有排队的功能,所以信号可能会被丢失。多个连续的信号来不及处理。

用waidpid()枚举检查不失为一种好的解决方法,见UNP 5.10


关于TOE(TCP offload engine)

本地抓包时一个小细节:


出现checksum incorrect。是由网卡上的TOE引擎造成的。

TOE wiki

用TCP/IP协议处理网络流量,要占用大量server资源。为了减轻server的压力,一种称为TCP减负引擎(TCP Offload Engine :TOE)的技术应运而生。

TCP减负引擎一般由软硬两部分组件构成,将传统的TIP/IP协议栈的功能进行延伸,把网络数据流量的处理工作所有转到网卡 上的集成硬件中进行,server仅仅承担TCP/IP控制信息的处理任务。
一般由操作系统的TCP/IP协议栈完毕TCP/UDP/IP校验和的计算工作,在网卡集成TOE的功能会包含计算checksum。

设置Rx Checksum Offload/Tx Checksum Offload为Enable之后,协议栈不再进行校验和的计算,而是由网卡自己完毕。


把网卡的属性改动一下就能够避免checksum incorrect,禁用 Checksum Offload。可修正checksum incorrect。代价是网络性能减少。


这个校验和的问题似乎相应用层的程序没有什么影响。。。(个人感觉)


Socket上的I/O处理

前文(标准I/O小结)提到的标准I/O库是ANSI C定义的一组高级输入输出函数,比起直接使用UNIX的系统I/O更加方便。
然而,标准I/O库没有提供读取文件元数据的方式,也不适合处理socket一类的特殊文件。


不足值(short count)
    定义,简而言之,我想处理10个字节,仅仅处理了6个。则不足值是6 。注意不是4
    因为内核中套接口的缓冲区大小有限和网络时延的原因,造成read和write实际处理的字节比预期的要少。其它如遇到EOF或从终端读取,也可能遇到不足值
读写磁盘文件时不会出现不足值


处理方式:
 UNP 3.9和CSAPP 10.9(RIO) 均给出了解决方法,借鉴之。例如以下代码:

int simon_send(int fd, char* buf, unsigned int n)
{
	int left = n;	
	char *bufptr = buf;
	int send_bytes;
	
	while (left >= 0)
	{
		if ((send_bytes = send(fd, bufptr, MAX_BUF_SIZE, 0)) < 0)  
		{
			if (errno == EINTR)  //iterrupted by signal , send again
				send_bytes = 0;
			else
				break;
		}
		else if (!send_bytes)  // EOF or socket shutdown by peer
			break;

		left -= send_bytes;
		bufptr += send_bytes;
	}

	return n - left;
}

int simon_recv(int fd, char* buf, unsigned int n)
{
	int left = n;	
	char *bufptr = buf;
	int recv_bytes;
	
	while (left >= 0)
	{
		if ((recv_bytes = recv(fd, bufptr, MAX_BUF_SIZE, 0)) < 0)
		{
			if (errno == EINTR)  
				recv_bytes = 0;
			else
				return -1;
		}
		else if (!recv_bytes) 
			break;

		left -= recv_bytes;
		bufptr += recv_bytes;
	}

	return n - left;
}
另,使用带标志MSG_WAITALL的recv也能一定程度上处理。


关于I/O的选择和比較。可见下图(摘自某ppt):




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值