zoukankan      html  css  js  c++  java
  • 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):




  • 相关阅读:
    第十二章学习笔记
    UVa OJ 107 The Cat in the Hat (戴帽子的猫)
    UVa OJ 123 Searching Quickly (快速查找)
    UVa OJ 119 Greedy Gift Givers (贪婪的送礼者)
    UVa OJ 113 Power of Cryptography (密文的乘方)
    UVa OJ 112 Tree Summing (树的求和)
    UVa OJ 641 Do the Untwist (解密工作)
    UVa OJ 105 The Skyline Problem (地平线问题)
    UVa OJ 100 The 3n + 1 problem (3n + 1问题)
    UVa OJ 121 Pipe Fitters (装管子)
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/5064569.html
Copyright © 2011-2022 走看看