TCP/IP HTTP协议分析
1.TCP/IP协议
1.1 select模型
int select(int nfds, fd_set *readset, fd_set *writeset,fd_set* exceptset, struct tim *timeout);
理解select模型的关键在于理解fd_set,为说明方便,取fd_set长度为1字节,fd_set中的每一bit可以对应一个文件描述符fd。则1字节长的fd_set最大可以对应8个fd。
(1)执行fd_set set; FD_ZERO(&set);则set用位表示是0000,0000。
(2)若fd=5,执行FD_SET(fd,&set);后set变为0001,0000(第5位置为1)
(3)若再加入fd=2,fd=1,则set变为0001,0011
(4)执行select(6,&set,0,0,0)阻塞等待
(5)若fd=1,fd=2上都发生可读事件,则select返回,此时set变为0000,0011。注意:没有事件发生的fd=5被清空。
基于上面的讨论,可以轻松得出select模型的特点:
- 可监控的文件描述符个数取决与sizeof(fd_set)的值。我这边服务器上sizeof(fd_set)=512,每bit表示一个文件描述符,则我服务器上支持的最大文件描述符是512*8=4096。据说可调,另有说虽 然可调,但调整上限受于编译内核时的变量值。本人对调整fd_set的大小不太感兴趣,参考中的模型2(1)可以有效突破select可监控的文件描述符上限。
- 将fd加入select监控集的同时,
还要再使用一个数据结构array保存放到select监控集中的fd,一是用于再select 返回后,array作为源数据和fd_set进行FD_ISSET判断。二是select返回后会把以前加入的但并无事件发生的fd清空,则每次开始 select前都要重新从array取得fd逐一加入(FD_ZERO最先),扫描array的同时取得fd最大值maxfd,用于select的第一个 参数。 - 可见select模型必须在select前
循环array(加fd,取maxfd),select返回后循环array(FD_ISSET判断是否有时间发生)。
1.2 使用select函数
使用select函数的过程一般是:先调用宏FD_ZERO将指定的fd_set清零,然后调用宏FD_SET将需要测试的fd加入fd_set,接着调用函数select测试fd_set中的所有fd,最后用宏FD_ISSET检查某个fd在函数select调用后,相应位是否仍然为1。
测试是否可读
int isCanRead(int nTimeOut)
{
fd_set readfds;
struct timeval timeout;
int iret;
timeout.tv_sec = (nTimeOut-nTimeOut%1000)/1000;
timeout.tv_usec = nTimeOut%1000;
FD_ZERO(&readfds);
FD_SET(mkssock,&readfds);
iret = select((int)mkssock+1,&readfds,NULL,NULL,&timeout);
if (SOCK_ERR == iret)
{
return SOCK_ERR;
}
if (0 == iret) //select超时
{
return -101;
}
if(FD_ISSET(mkssock,&readfds))
{
return 0;
}
return SOCK_ERR;
}
测试是否可写
int isCanWrite(int nTimeOut)
{
fd_set writeds;
struct timeval timeout;
int iret;
timeout.tv_sec = (nTimeOut-nTimeOut%1000)/1000;
timeout.tv_usec = nTimeOut%1000;
FD_ZERO(&writeds);
FD_SET(mkssock,&writeds);
iret = select((int)mkssock+1,NULL,&writeds,NULL,&timeout);
if (SOCK_ERR == iret)
return SOCK_ERR;
if (0 == iret) //select超时
{
return -101;
}
if(FD_ISSET(mkssock,&writeds))
{
return 0;
}
return SOCK_ERR;
}
2.HTTP协议
HTTP协议通常承载于TCP协议之上,有时也承载于TLS或SSL协议层之上,这个时候,就成了我们常说的HTTPS.
默认HTTP的端口号为80,HTTPS的端口号为443。无法实现在客户端没有发起请求的时候,服务器将消息推送给客户端。
HTTP协议是一个无状态的协议,同一个客户端的这次请求和上次请求是没有对应关系.
2.1 主要特点
-
简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。 -
灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。 -
无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。 -
无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。 -
支持B/S及C/S模式。
3.一些小工具
3.1 Wireshark 抓包工具
比如需要查看TCP3次握手具体情况,可以用抓包工具查看。
4.附录
4.1 select模型中补充
- 1.mkssock = socket(AF_INET,SOCK_STREAM,0);
-
2.接收返回代码片段
//先读4个字节长度 while(1) { iret = ZTrecv(buffer,4-iOffset,timeousms ); if(iret > 0 ) { iOffset += iret; if(iOffset > 3) { memcpy(tmp ,buffer, 4); NeedRecvLen = atoi(tmp ); break; } LogMsg(“ This Time Recv [%d]Data” , iret) ; timeousms = 5000; continue; } else { LogMsg(“Recv Data Len —[%d][%d]” , iret ,iOffset) ; return TMS_UPLOAD_RSP_FAIL; } }
iOffset = 0 ;iret= 0 ;timeousms = RCV_TIMEOUT_S * 1000; while(1) { iret = ZTrecv(buffer+4+iOffset, NeedRecvLen-iOffset,timeousms ); if(iret > 0 ) { iOffset += iret; if(iOffset > (NeedRecvLen-1 ) ) { break; } timeousms = 5000; continue; } else { LogMsg(“Recv Data Result —[%d][%d]” , iret ,iOffset) ; return TMS_UPLOAD_RSP_FAIL; }
}
4.2 学习更多可以访问
- http协议学习
- http协议入门
- TCP/IP协议的select模型设置
- select、poll、epoll之间的区别总结
- Linux IO模式及 select、poll、epoll详解
- Linux下select, poll和epoll IO模型的详解
扫描关注我
(转载本站文章请注明作者和出处 Undefined)