(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
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
底层实现,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 ); } |
不仅仅是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; } |
注意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; } |
将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 测试程序