`

Select代码理解

 
阅读更多

Socket代码理解

1 socket select流程

(1)初始化server socket

initServerSocket

(2)监管 server socket

FD_SET ( gehServerFd, &readFdsMaster );

(3)更新socket fd最大值

UPDATE_MAXFD ( gehServerFd );

(4)循环等待数据

while ( 1 )

rv = select ( maxFdTmp + 1, &readFdsMasterTmp, NULL, NULL, NULL );

(5)select三种返回值的判断

(6)检测是哪个fd有数据

if ( !FD_ISSET ( actualFd, &readFdsMasterTmp ) )

(7)两种情况:server socket有新连接或者client socket有数据可读

if ( actualFd == gehServerFd )

if ( actualFd != gehServerFd )

(8)server socket有新连接,则accept并监管和更新fd最大值

if ( 4 > ( connFd = accept ( gehServerFd, ( SA * ) & cliAddress, &sockAddressLen ) ) )

FD_SET ( connFd, &readFdsMaster );

UPDATE_MAXFD ( connFd );

(9)client socket有新数据,则接收

ehRead

2 select关键点

two match

(1).fd_set in select match fd_set in FD_ISSET

It can be changed in select

(2).maxfd in select match maxfd in for

It can be changed in listenfd

3 KEEP Alive

底层实现,AP层不用关心

tcmRet initKeepAlive()

{

system("echo 10 > /proc/sys/net/ipv4/tcp_keepalive_time");

system("echo 2 > /proc/sys/net/ipv4/tcp_keepalive_intvl");

system("echo 3 > /proc/sys/net/ipv4/tcp_keepalive_probes");

return TCMRET_SUCCESS;

}

tcmRet setKeepAlive( int kvFd )

{

int keepAliveFlag = 1;

int ret;

ret = setsockopt(kvFd,SOL_SOCKET,SO_KEEPALIVE,(void *)&keepAliveFlag,sizeof(keepAliveFlag));

return ( (ret == 0) ? TCMRET_SUCCESS:TCMRET_FAILURE );

}

4 Error check

不仅仅是check error,并且还有clear error的作用。

getsockopt ( actualFd, SOL_SOCKET, SO_ERROR, &error, ( socklen_t * ) &errlen );

if( error == -1 )

{

tcmLog_debug( "Before accept actualFd == gehServerFd This socket %d is error no is %d errlen is %d, /

so we donot accept it", actualFd, error, errlen );

continue;

}

5 read 和write结构体数据

注意tail部数据的读取或发送

typedef struct EHOMEPROTOCOLMSG

{

uint16_t protocolVersion;

uint16_t payloadLen;

uint8_t reserve[16];

/**************Overhead is the message header*******************/

uint16_t eventType;

uint16_t valueLen;

}EhomeProtocolMsg;

tcmRet ehRead ( int rdFd, EhomeProtocolMsg** rdBuf, unsigned int rdTimeout )

{

tcmLog_debug ( "Start fd read message" );

EhomeProtocolMsg* msgTmp;

int rc;

tcmRet ret;

if ( rdBuf == NULL )

{

return TCMRET_INVALID_PARAMETER;

}

else

{

*rdBuf = NULL;

}

msgTmp = ( EhomeProtocolMsg * ) malloc ( sizeof ( EhomeProtocolMsg ) );

if ( msgTmp == NULL )

{

return TCMRET_INTERNAL_ERROR;

}

rc = read ( rdFd, msgTmp, sizeof ( EhomeProtocolMsg ) );

printf( "First read header data length is %d", rc );

if ( ( rc == 0 ) ||

( ( rc == -1 ) && ( errno == 131 ) ) ) /* new 2.6.21 kernel seems to give us this before rc==0 */

{

printf( "First read rc == -1 or 0/n" );

/* broken connection */

free ( msgTmp );

return TCMRET_DISCONNECTED;

}

else if ( rc < -1 || rc != sizeof ( EhomeProtocolMsg ) )

{

printf( "First read rc < -1/n" );

free ( msgTmp );

return TCMRET_DISCONNECTED;

}

uint16_t valueLenTmp = msgTmp->valueLen;

msgTmp->valueLen = ntohs(valueLenTmp);

if ( msgTmp->valueLen > 0 )

{

int totalReadSoFar = 0;

int totalRemaining = msgTmp->valueLen;

char *inBuf;

/* there is additional data in the message */

msgTmp = ( EhomeProtocolMsg * ) realloc ( msgTmp, sizeof ( EhomeProtocolMsg ) + /

msgTmp->valueLen );

if ( msgTmp == NULL )

{

free ( msgTmp );

return TCMRET_INTERNAL_ERROR;

}

inBuf = ( char * ) ( msgTmp + 1 );

while ( totalReadSoFar < msgTmp->valueLen )

{

rc = read ( rdFd, inBuf, totalRemaining );

printf( "Second read data length is %d/n", rc );

if ( ( rc == 0 ) ||

( ( rc == -1 ) && ( errno == 131 ) ) )

{

printf( "Second read rc == 0 or -1/n" );

free ( msgTmp );

return TCMRET_DISCONNECTED;

}

else if ( rc < -1 )

{

printf( "Second read rc < -1 /n" );

free ( msgTmp );

return TCMRET_DISCONNECTED;

}

else

{

inBuf += rc;

totalReadSoFar += rc;

totalRemaining -= rc;

}

}

}

/**************************Hex printf**************************/

tcmLog_debug( "Read HEX buf from socket fd %d", rdFd );

if( (sizeof ( EhomeProtocolMsg ) + msgTmp->valueLen) < 200 )

dump( msgTmp, sizeof ( EhomeProtocolMsg ) + msgTmp->valueLen );

/***************************************************************/

*rdBuf = msgTmp;

return TCMRET_SUCCESS;

}

tcmRet ehWrite ( int wtFd, EhomeProtocolMsg* wtBuf )

{

unsigned int totalLen;

int rc;

tcmRet ret = TCMRET_SUCCESS;

uint16_t valueLenTmp = ntohs(wtBuf->valueLen);

totalLen = sizeof ( EhomeProtocolMsg ) + valueLenTmp;

/**************************Hex printf******************************/

tcmLog_debug( "Write HEX buf to socket fd %d", wtFd );

if( totalLen < 200 )

dump( wtBuf, totalLen );

/*******************************************************************/

rc = write ( wtFd, ( char * ) wtBuf, totalLen );

if ( rc < 0 )

{

if ( errno == EPIPE )

{

/*

* This could happen when smd tries to write to an app that

* has exited. Don't print out a scary error message.

* Just return an error code and let upper layer app handle it.

*/

return TCMRET_DISCONNECTED;

}

else

{

ret = TCMRET_INTERNAL_ERROR;

}

}

else if ( rc != ( int ) totalLen )

{

ret = TCMRET_INTERNAL_ERROR;

}

return ret;

}

6 十六进制的输出

将read和write的数据,均以十六进制的格式输出

void dtoh(uint8_t * hex,uint8_t n)

{

static const uint8_t HEX[] = "0123456789ABCDEF";

hex[0] = HEX[n / 16];

hex[1] = HEX[n % 16];

}

void dump_block(char * in,char * out,int len)

{

int cur;

for (cur = 0; cur < len; cur++)

{

dtoh(out + 2 * cur,in[cur]);

}

}

void hex_disp(char * in,int len,int size)

{

int cur = 0;

int row_cnt = 0;

//tcmLog_debug("%08dh:",row_cnt++);

char* bufTmp = (unsigned char *)malloc(len * 4 + 1);

memset( bufTmp , 0, len*4 + 1 );

char* pbufTmp = bufTmp;

do

{

sprintf( pbufTmp + strlen( bufTmp ) ,"%-3.2s " ,in + size * cur);

cur++;

if (cur % 8 == 0)

{

//tcmLog_debug("/n%08dh:",row_cnt++);

}

}

while(cur < len);

pbufTmp[strlen(bufTmp)]='/0';

tcmLog_debug( "%s", pbufTmp );

free(bufTmp);

}

#ifdef _NOT_PRINTF_HEX_

void dump (char * in,int len)

{

unsigned char * out = (unsigned char *)malloc(len * 2 + 1);

dump_block(in,out,len);

hex_disp(out,len,2);

free(out);

}

#endif

#ifndef _NOT_PRINTF_HEX_

void dump (char * in,int len)

{

}

#endif

7 测试程序

http://download.csdn.net/source/3119181

分享到:
评论

相关推荐

    select模型代码实现

    通过分析这些代码,你可以更深入地理解`select`模型如何应用于实际项目中,以及如何优化并发性能和提高系统资源利用率。 总的来说,`select`模型是网络编程中一种基础但实用的多路复用机制,它帮助开发者在有限的...

    jQuery模拟Select下拉菜单选中添加代码.zip

    《jQuery模拟Select下拉菜单选中添加代码》 在网页开发中,Select下拉菜单是一种常见的用户交互元素,用于提供多个选项供用户选择。然而,原生的HTML Select标签有时不能满足设计师和开发者对于界面美观性和交互性...

    JS模拟IOS联动选择插件iosselect代码

    - `src`:源代码目录,包含了未压缩和未合并的js和css文件,便于理解和调试。 - `demo`:可能包含更多的示例或测试用例,帮助开发者理解插件的不同用法和功能。 通过研究这些文件,开发者可以深入了解iosselect的...

    tcp测试客户端代码,实现select模式下客户端tcp连接器

    通过阅读和理解这段代码,开发者可以学习到如何在C++中构建一个功能完备的TCP客户端,并使用select模型来实现高效的并发连接。 总结来说,这个TCP测试客户端代码是学习网络编程和C++多路复用I/O的一个好例子。通过...

    JS模拟IOS联动选择插件iosselect代码.zip

    【JS模拟IOS联动选择插件iosselect代码.zip】是一个针对前端开发者的实用工具,它提供了JavaScript实现的iOS风格联动选择效果。这个插件对于那些希望在网页应用中模仿iOS设备上选择器行为的开发者来说非常有用。通过...

    jQuery模拟select下拉框三级城市联动代码.zip

    这个"jQuery模拟select下拉框三级城市联动代码.zip"压缩包提供的就是一个使用jQuery库来实现这种效果的示例。这里我们将深入探讨相关知识点。 首先,jQuery是一个广泛使用的JavaScript库,它简化了DOM操作、事件...

    select头像选择代码

    总的来说,"select头像选择代码"涉及到了JavaScript基础、DOM操作、事件处理、File API、表单交互等多个前端开发的重要知识点。掌握这些技能,开发者可以创建出更加互动、用户体验优秀的Web应用。在实际项目中,可能...

    编译原理first,select,follow实验源代码

    这些概念在编译器设计中扮演着重要角色,帮助我们理解如何从源代码转换为可执行程序。 1. **First集合** First集合是一个非终结符的集合,包含了在该非终结符开始的所有可能的符号序列。如果非终结符A可以以某个...

    UDP协议的select模型代码

    首先,我们要理解`select`函数的工作原理。`select`模型通过监视文件描述符集,判断哪些描述符有可读、可写或异常事件。在UDP协议中,`select`通常用于检测是否有新的UDP数据包到达,或者是否可以发送数据。 以下是...

    select 监控多个客户端代码

    本文将深入探讨`select`函数的工作原理、使用方法以及其在监控多个客户端代码中的应用。 `select`函数是一个系统调用,它允许程序同时监控多个文件描述符(通常是套接字)的状态,以查看哪些文件描述符已经准备好...

    JSP+AJAX实现两级select联动 代码

    JSP是Java的一种服务器端脚本语言,它允许开发者在HTML页面中嵌入Java代码,从而动态生成网页内容。JSP在服务器上运行,生成HTML后发送到客户端浏览器,使得服务器可以处理复杂的业务逻辑和数据操作,如与数据库的...

    jsp select 带多选框

    而"源码"标签可能意味着博主提供了实际的代码片段或完整的示例项目,帮助读者更好地理解和应用这个概念。 "工具"标签可能是指使用了一些辅助开发工具,比如IDE(如Eclipse、IntelliJ IDEA)、构建工具(如Maven、...

    jQuery模拟Select下拉菜单选中添加代码

    首先,我们需要理解原生HTML的`&lt;select&gt;`元素及其`&lt;option&gt;`子元素。`&lt;select&gt;`用于创建一个下拉列表,而`&lt;option&gt;`则表示列表中的可选项。然而,原生的`&lt;select&gt;`在样式定制和交互性方面有限,因此开发者常常使用...

    简单的Socket select模式源代码(server,client)

    首先,我们需要理解`select`的基本语法: ```c #include &lt;sys/select.h&gt; int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); ``` - `nfds`: 监控的最大文件...

    jQuery Select下拉框美化代码

    **jQuery Select下拉框美化代码**是用于提升网站交互体验的一种技术手段,它通过使用JavaScript库jQuery和特定的插件,如本例中的`ui-select.js`,来增强和美化HTML中的`&lt;select&gt;`元素。在传统的网页设计中,`...

    jquery select下拉框美化代码.zip

    在网页设计中,下拉框(Select)是一个常见的表单元素,用于用户选择多个选项中的一个。..."jquery select下拉框美化代码.zip" ...通过深入理解并适当地应用这些代码,开发者可以进一步提升其网站或应用程序的用户体验。

    3c. 16-bit Carry-Select Adder_Carry_carryskipadder_

    16-bit Carry-Select Adder"可能包含详细的设计图、逻辑电路图、Verilog或VHDL代码示例,以及关于如何实现16位Carry-Skip加法器的步骤和性能分析。对于电子工程师和计算机科学家来说,理解这些内容有助于他们设计更...

    js+css美化select,简单易用代码少,可以自己控制样式

    这篇博客"js+css美化select,简单易用代码少"探讨了如何利用这两种技术实现这一目标,而且重点在于代码简洁,易于理解。 首先,我们需要理解JavaScript的作用。JavaScript可以用来动态地操作DOM(文档对象模型),...

    双选框 两个<select>标签组成 高效代码清晰

    首先,我们要理解这两个`&lt;select&gt;`标签如何协同工作。通常,一个`&lt;select&gt;`元素允许用户选择一个或多个(如果设置`multiple`属性)选项。在这个案例中,用户可以从左侧的`&lt;select&gt;`选择元素,然后通过某种交互方式...

    layui问题之模拟select点击事件的实例讲解

    - **自动触发下拉**: 通过JavaScript代码模拟用户操作,触发select的下拉框。 - **选择特定选项**: 自动点击下拉框中的特定选项。 #### 示例代码 - 使用jQuery选择器和`click()`方法来模拟用户点击操作,实现自动...

Global site tag (gtag.js) - Google Analytics