`

阻塞和非阻塞的一点使用心得

阅读更多
在《unp》书上,stevent一开始的一个服务器小例子这样介绍到:一个TCP的服务器和客户

端,客户端puts进行阻塞式的输入消息。暴露的问题是,当用户进行阻塞到puts输入时,对方

的服务器关闭,那么用户可能发了一大断消息按下发送时,发现程序崩溃了。。阻塞的出现的

另一种意义就是各司职。 最近在负责的一个项目中,需要频繁的进行TCP吞吐,我一时认为不


需要什么阻塞,都是即时的消息,而且又很频繁。结果暴露的问题出来了:(9060为服务端)
1、如
tcp        0  16385 218.66.25.238:32821     218.66.25.238:9060      FIN_WAIT1 
tcp    60416      0 218.66.25.238:9060      218.66.25.238:32821     ESTABLISHED

tcp        0     36 218.66.25.238:22        218.66.25.222:1874      ESTABLISHED 
tcp        0      0 218.66.25.238:32821     218.66.25.238:9060      TIME_WAIT 


哦是的,我卡住了。我在发送数据的时候阻塞了。而且当我我把客户端关闭时,发送第一个

TCP FIN后,客户端状态为FIN_WAIT1,这时我期待着对方的返回。(TCP SYS 和 socket fin)

可是,看到60416了吗,服务器的缓冲区满了。我不得不等到服务套接字将他们都取完后才结

束。但是这个阻塞影响了我一些线程方面的判断。或许你会说, 谁叫你把recv和send设置得

不一样。这个我承认,但是你也得考虑到,万一网速不那么顺畅,可能会造成一方发送较快,

导致在缓冲区里累计一些包,长久以后,程序必然崩溃;当然还包括当你机器繁忙时,recv和

send执行得也许不那么顺利呢?这些都是隐患。
 
所以考虑下,决定用select执行。代码如下:

int CCreateTCP_UDP::Writen(int fd, const void *vptr, size_t n)
{
	size_t		nleft;
	ssize_t		nwritten;
	const char	*ptr;

	ptr = (const char*)vptr;
	nleft = n;
	while (nleft > 0) 
	{
		if ( (nwritten = write(fd, ptr, nleft)) <= 0) 
		{
			if (errno == EINTR)
				nwritten = 0;		/* and call write() again 

*/
			else
				return(-1);			/* error */
		}

		nleft -= nwritten;
		ptr   += nwritten;
	}
	return(n);
}

int CCreateTCP_UDP::WritenUBlock(int fd, const void *vptr, size_t n)
{
	fd_set		set_write;
	timeval   time_out; 

	FD_ZERO(&set_write);
	FD_SET(fd, &set_write);
	time_out.tv_sec=time_out.tv_usec=3; //可能会被改变
	if( select(fd+1, NULL, &set_write, NULL, &time_out)==-1 )
	{
		return -1;	
	}
	/*select可能返回>0的数,为了防止0套接字,进行个判断
		所以这里要注意保持收和发的平衡性
		尽量减少缓冲区的饱和
  */
	if( FD_ISSET(fd, &set_write) )
	{
		/*为了防止数据上的一些连包,返回错误重新处理*/
		if( Writen( fd, vptr, n )!=n)
		{
			return -1;	
		}
	}
	/*成功的话,理所当然返回发送的字节数,不过既然能通过!=n,
	  就简单的以统一的0表示成功*/
	return 0;
}


一些代码是照抄《unp》上的。

这里做点解释:在WritenUBlock这个函数里,首先将套接字放入FD_SET的类型,接着用select

查询。用select我们当然希望它当套接字可以用时告诉我们。

可以有如下几个情况(总结的不是很完全)

1 当缓冲区中的数据满足读的条件(比如你的套接字至少要10个字节,而这时候缓冲区中的数

据长度满足)

2 当socket发生错误时。这里大家可能不明白,为什么要socket发生错误时。很好理解,当我

们用一个套接字时,最希望的是当它可以用的时候告诉我们,起码使用它时不会崩溃。既然这

样的话,发生错误是不是也在我们范围之内呢?

错误有两种,
一是1;这表示发生了一个调用错误,要和普通的数据接收错误分开,这是一个函数的调用错误

二是0;很不幸,这表示它读到了一个EOF字符。表示对方要跟你断开了,这里细节如下:当对

方进程结束或者调用close,对方的TCP首先发送一个FIN,我方回复这个FIN,接着我方的TCP向

这个套接字的缓冲区送一个EOF,等带着套接字调用,当我方套接字收到这个0,就发送一个

socket的FIN,对方接着回复这个FIN。一环扣着一环,具体见我上一篇BLOG,《time_wait状

态的解释和验证》。

这就是今天我对阻塞和非阻塞的一点认识,当然对select的工作系统还不熟悉,只是初步的使











2
1
分享到:
评论
1 楼 lin_style 2008-06-17  
再教大家一个方法
当你跟对方对接时,你可以不接收。
当你缓冲区满时,对方就会阻塞,如果对方代码做的判断不好,就可能导致程序崩溃^_^

相关推荐

    socket_recv函数使用心得.

    socket_recv 函数使用心得 在学习 socket_recv 函数时,需要了解其返回值的含义和使用场景。在阻塞模式下,当网络异常时,recv 函数返回值为-1,表示连接异常,需要关闭连接。在非阻塞模式下,如果没有数据,recv ...

    Netty使用心得,Netty实战

    6. **易于使用和扩展**:Netty 的 API 设计简洁,方便开发者理解和使用,同时提供了丰富的扩展点,允许自定义各种组件以满足特定需求。 在 Netty 实战中,我们通常会遇到以下场景: 1. **创建服务器**:通过 ...

    《Oracle9i&10g编程艺术》学习心得

    其中,绑定变量和非阻塞读是两个非常重要的概念,对于提高Oracle应用程序的性能和稳定性具有重要意义。通过对这些知识点的学习和实践,开发者可以更好地利用Oracle的强大功能,构建高效稳定的数据库应用。

    verilog学习心得

    然而,always块中的敏感列表和非阻塞赋值()用于描述顺序行为,这是理解和调试Verilog设计的关键。 5. **状态机设计**:状态机是Verilog中常见的一种设计模式,用于控制系统的流程。学会如何用Verilog描述Mealy型...

    Linux设备驱动程序学习心得

    在Linux系统中,设备驱动程序是内核的一部分,它们使得操作系统能够高效地管理和使用各种硬件资源。 "Linux设备驱动程序学习心得"主要围绕着"LDD3",即《Linux Device Drivers》第三版这本书展开。LDD3是一本经典的...

    netty部分参考个人心得

    * I/O 模型:使用非阻塞 I/O 模型,基于 I/O 复用模型,使用 Selector 对象对多路复用器进行管理 * 线程处理模型:使用 NioEventLoop 线程池,聚合了多路复用器 Selector,可以同时并发处理成百上千个客户端连接 ...

    程序员心得

    4. **IO与NIO**:了解输入/输出流的使用,以及Java NIO(非阻塞I/O)的优势和应用场景。 5. **多线程**:学习如何创建和管理线程,理解线程同步与通信,如synchronized关键字、wait()和notify()方法等。 6. **反射...

    201年最新学习java心得

    Java的IO流模型处理输入输出操作,NIO则提供了非阻塞I/O操作,适用于高并发场景。此外,多线程编程也是Java的一大特色,线程同步和互斥的机制,如synchronized关键字和Lock接口,能够帮助开发者构建高效的并发程序。...

    java并发个人心得

    - **优先考虑非阻塞算法**:在可能的情况下,使用非阻塞算法可以提高程序的效率。 - **正确处理异常**:在多线程环境中,正确处理异常尤为重要,因为异常可能会导致线程挂起或资源泄漏等问题。 - **避免过度使用线程...

    Matlab 数据传递心得

    8. **数据流与管道**:在处理大量数据时,可以利用MATLAB的流数据处理功能,例如使用`readasync`和`writeasync`函数实现数据的非阻塞读写,以连续、高效的方式传递和处理大数据。 9. **内存管理与性能优化**:理解...

    2021-2022年收藏的精品资料软件工程师15个值得开发者关注的jQuery开发技巧和心得.docx

    在本文档中,我们探讨了15个对软件工程师尤其是jQuery开发者至关重要的技巧和心得,旨在帮助他们提高代码效率和性能。以下是对这些技巧的详细解释: 1. **使用最新版本的jQuery库**:更新到最新版本的jQuery是提高...

    Java相关技术的源码学习心得

    深入学习GC的工作原理,包括分代收集、可达性分析、各种GC算法(如Serial、Parallel、CMS、G1、ZGC等),可以帮助优化内存使用和避免内存泄漏。 3. **并发与多线程**:Java提供了丰富的并发API,如synchronized、...

    Core Java心得笔记

    NIO(New IO)提供非阻塞I/O操作,提高了效率。 10. **线程**:Java内置对多线程的支持,通过Thread类或实现Runnable接口创建线程。线程同步机制(如synchronized关键字、wait(), notify(), notifyAll()方法)防止...

    node.js的旅游网站设计浅析-网站设计-设计.pdf

    1. 基于事件机制: Node.js 是一个基于事件机制的框架, Node.js 部分的模块都继承自 Event 模块,实现了简单的事件模式的实现,将常见且成熟的技术引入到后端,实现和异步非阻塞 I/O 的配合。 2. 异步非阻塞 I/O:...

    微软编程技术面试心得

    4. **操作系统**:理解进程与线程的概念,掌握同步与互斥机制(如信号量、锁、条件变量),了解内存管理(虚拟内存、内存分配与释放)和I/O模型(同步异步、阻塞非阻塞)。 5. **计算机网络**:理解TCP/IP五层模型...

    编程心得,基于320

    此外,它还体现了在嵌入式系统中优化资源使用的重要性,如通过中断服务程序实现非阻塞式的数据处理,以及在低功耗设备上进行有效的电源管理。对于其他类似应用,开发者可以借鉴这种方法,根据实际需求调整阈值和处理...

    ORACLE学习心得

    Oracle数据库是全球广泛使用的大型企业级数据库管理系统,其性能优化和设计原则对于任何IT专业人员来说都是至关重要的。本文将围绕“ORACLE学习心得”展开,深入探讨Oracle数据库的优化策略、并发控制、数据库设计...

Global site tag (gtag.js) - Google Analytics