C 实现HTML5服务时,遇到握手状态的判断问题...
16lz
2021-01-22
下面是服务器接受函数的代码:
如果是某个客户端第一次连接服务器,则建立握手先,以后,该连接除非重新连接服务器再,则不需要握手动作,做普通SOCKET通信
但是,下面代码作判断时,服务器只能与一个客户端建立连接,其他客户端就不能再连接上了,服务建立握手...
当多个客户端存在时,如何判断每一个客户端是否是第一次与服务器连接,以便建立握手?
相对全一点的代码,代码都是来自网络,目前这样方式,只能接受一个客户端连接,并交互通信。
如何在客户端建立连接时,为每个客户端,标记一个状态,如果是第一次连接,则标记一个状态,以便完成握手动作,
握手后,修改状态,直到该客户端关闭连接再恢复该状态,,方便该客户端下次连接服务器以完成握手。
如果是某个客户端第一次连接服务器,则建立握手先,以后,该连接除非重新连接服务器再,则不需要握手动作,做普通SOCKET通信
但是,下面代码作判断时,服务器只能与一个客户端建立连接,其他客户端就不能再连接上了,服务建立握手...
当多个客户端存在时,如何判断每一个客户端是否是第一次与服务器连接,以便建立握手?
//receivedata
voidRecvData(intfd,intevents,void*arg)
{
unsignedcharret_len;
unsignedcharsend_str[254];
structmyevent_s*ev=(structmyevent_s*)arg;
intlen,i;
memset(ev->buff,0,REQUEST_LEN_MAX);
len=recv(fd,ev->buff,sizeof(ev->buff),0);
//printf("---------------------\n");
printf("recvdatalen:%d\n",len);
//printf("---------------------\n");
//printf("recvdatacontent:%s\n",ev->buff);
printf("\n");
if(len<480){
//printf("recvdatacontent:\n");
for(i=0;i<len;i++)
printf("%02x",ev->buff[i]);
}
printf("\n");
if((0==connected))//目前只能接受一个客户端的连接握手,当第二个客户端请求连接时,就走不到握手协议这里,也就无法建立连接....
{
printf("shakehandisok%d\n",fd);
//printf("read:%d\n%s\n",len,ev->buff);
secWebSocketKey=computeAcceptKey(ev->buff);
shakeHand(fd,secWebSocketKey);
connected=1;
//printf("22222connectedis:%d\n",connected);
//continue;
}
/*
data=analyData(ev->buff,len);
printf("dataconent:%s\n",ev->buff);
printf("datalen:%d\n",len);
response(fd,data);
*/
if(len<254){
ret_len=analyData_2(ev->buff,len,send_str);
//printf("254content:\n");
//for(i=0;i<ret_len;i++)
//printf("%02x",send_str[i]);
}
if(len==6&ev->buff[0]==0x88)//页面上断开连接
{
//printf("3333connectedis:%d\n",connected);
connected=0;
close(ev->fd);
printf("[fd=%d]pos[%d],closedgracefully.\n",fd,ev-g_Events);
//printf("4444connectedis:%d\n",connected);
}
if(len>0)
{
ev->buff[0]=0x81;
ev->buff[1]=12;
ev->buff[2]=0x46;
ev->buff[3]=0x30;
ev->buff[4]=0x30;
ev->buff[5]=0x36;
ev->buff[6]=0x45;
ev->buff[7]=0x45;
ev->buff[8]=0x30;
ev->buff[9]=0x31;
ev->buff[10]=0x32;
ev->buff[11]=0x33;
ev->buff[12]=0x42;
ev->buff[13]=0x43;
ev->buff[14]=0x42;
ev->buff[15]=0x43;
ev->len+=len;
printf("\n");
//ev->buff[0]=buffer[0];
//ev->buff[1]=buffer[1];
//memcpy(ev->buff,buffer,buffer[1]+2);
ev->len=14;
ev->call_back=SendData;
//changetosendevent
//EventSet(ev,fd,SendData,ev);
EventAdd(g_epollFd,EPOLLOUT,ev);
}
elseif(len==0)
{
close(ev->fd);
printf("[fd=%d]pos[%d],closedgracefully.\n",fd,ev-g_Events);
}
else
{
close(ev->fd);
printf("recv[fd=%d]error[%d]:%s\n",fd,errno,strerror(errno));
}
}
7 个解决方案
#1
相对全一点的代码,代码都是来自网络,目前这样方式,只能接受一个客户端连接,并交互通信。
如何在客户端建立连接时,为每个客户端,标记一个状态,如果是第一次连接,则标记一个状态,以便完成握手动作,
握手后,修改状态,直到该客户端关闭连接再恢复该状态,,方便该客户端下次连接服务器以完成握手。
#defineREQUEST_LEN_MAX1024
#defineDEFEULT_SERVER_PORT8000
#defineWEB_SOCKET_KEY_LEN_MAX256
#defineRESPONSE_HEADER_LEN_MAX1024
#defineLINE_MAX256
#defineHOST_IP_ADDRESS_TCP"192.168.34.52"
#defineMAX_EVENTS500
#defineHOST_PORT_TCP4530
intconnected=0;//0:notconnect.1:connected.
structmyevent_s
{
intfd;
void(*call_back)(intfd,intevents,void*arg);
intevents;
void*arg;
intstatus;//1:inepollwaitlist,0notin
unsignedcharbuff[1024];//recvdatabuffer
intlen,s_offset;
longlast_active;//lastactivetime
};
//setevent
voidEventSet(structmyevent_s*ev,intfd,void(*call_back)(int,int,void*),void*arg)
{
ev->fd=fd;
ev->call_back=call_back;
ev->events=0;
ev->arg=arg;
ev->status=0;
bzero(ev->buff,sizeof(ev->buff));
ev->s_offset=0;
ev->len=0;
ev->last_active=time(NULL);
}
//add/modaneventtoepoll
voidEventAdd(intepollFd,intevents,structmyevent_s*ev)
{
structepoll_eventepv={0,{0}};
intop;
epv.data.ptr=ev;
epv.events=ev->events=events;
if(ev->status==1){
op=EPOLL_CTL_MOD;
}
else{
op=EPOLL_CTL_ADD;
ev->status=1;
}
if(epoll_ctl(epollFd,op,ev->fd,&epv)<0)
printf("EventAddfailed[fd=%d],evnets[%d]\n",ev->fd,events);
else
printf("EventAddOK[fd=%d],op=%d,evnets[%0X],status:[%d]\n",ev->fd,op,events,ev->status);
}
//deleteaneventfromepoll
voidEventDel(intepollFd,structmyevent_s*ev)
{
structepoll_eventepv={0,{0}};
if(ev->status!=1)return;
epv.data.ptr=ev;
ev->status=0;
epoll_ctl(epollFd,EPOLL_CTL_DEL,ev->fd,&epv);
}
intg_epollFd;
structmyevent_sg_Events[MAX_EVENTS+1];//g_Events[MAX_EVENTS]isusedbylistenfd
voidRecvData(intfd,intevents,void*arg);
voidSendData(intfd,intevents,void*arg);
//acceptnewconnectionsfromclients
voidAcceptConn(intfd,intevents,void*arg)
{
structsockaddr_insin;
socklen_tlen=sizeof(structsockaddr_in);
intnfd,i;
//accept
if((nfd=accept(fd,(structsockaddr*)&sin,&len))==-1)
{
if(errno!=EAGAIN&&errno!=EINTR)
{
}
printf("%s:accept,%d",__func__,errno);
return;
}
do
{
for(i=0;i<MAX_EVENTS;i++)
{
if(g_Events[i].status==0)
{
break;
}
}
if(i==MAX_EVENTS)
{
printf("%s:maxconnectionlimit[%d].",__func__,MAX_EVENTS);
break;
}
//setnonblocking
intiret=0;
if((iret=fcntl(nfd,F_SETFL,O_NONBLOCK))<0)
{
printf("%s:fcntlnonblockingfailed:%d",__func__,iret);
break;
}
//addareadeventforreceivedata
EventSet(&g_Events[i],nfd,RecvData,&g_Events[i]);
EventAdd(g_epollFd,EPOLLIN,&g_Events[i]);
}while(0);
printf("newconn%s,%d,time:%ld,pos:%d\n",inet_ntoa(sin.sin_addr),
ntohs(sin.sin_port),g_Events[i].last_active,i);
}
//receivedata
//帖子内容大小有限制,放主贴里了
//senddata
voidSendData(intfd,intevents,void*arg)
{
structmyevent_s*ev=(structmyevent_s*)arg;
intlen,i;
//senddata
len=send(fd,ev->buff+ev->s_offset,ev->len-ev->s_offset,0);
if(len>0)
{
//printf("send[fd=%d],[%d<->%d]%s\n",fd,len,ev->len,ev->buff);
printf("senddatais:\n");
for(i=0;i<ev->buff[1]+2;i++)
printf("%02X",ev->buff[i]);
printf("\n");
ev->s_offset+=len;
if(ev->s_offset==ev->len)
{
//changetoreceiveevent
EventDel(g_epollFd,ev);
EventSet(ev,fd,RecvData,ev);
EventAdd(g_epollFd,EPOLLIN,ev);
}
}
else
{
close(ev->fd);
EventDel(g_epollFd,ev);
printf("send[fd=%d]error[%d]\n",fd,errno);
}
}
voidInitListenSocket(intepollFd,shortport,char*ip)
{
intlistenFd=socket(AF_INET,SOCK_STREAM,0);
fcntl(listenFd,F_SETFL,O_NONBLOCK);//setnon-blocking
printf("serverlistenfd=%d\n",listenFd);
EventSet(&g_Events[MAX_EVENTS],listenFd,AcceptConn,&g_Events[MAX_EVENTS]);
//addlistensocket
EventAdd(epollFd,EPOLLIN,&g_Events[MAX_EVENTS]);
//bind&listen
structsockaddr_insin;
bzero(&sin,sizeof(sin));
sin.sin_family=AF_INET;
//sin.sin_addr.s_addr=INADDR_ANY;
//sin.sin_addr.s_addr=inet_addr(HOST_IP_ADDRESS_TCP);
sin.sin_addr.s_addr=inet_addr(ip);
sin.sin_port=htons(port);
bind(listenFd,(structsockaddr*)&sin,sizeof(sin));
listen(listenFd,5);
printf("serveripis:%s\n",ip);
}
intmain(intargc,char*argv[])
{
structsockaddr_inservaddr,cliaddr;
socklen_tcliaddr_len;
intlistenfd,connfd;
charbuf[REQUEST_LEN_MAX];
char*data;
charstr[INET_ADDRSTRLEN];
char*secWebSocketKey;
inti,n;
//intconnected=0;//0:notconnect.1:connected.
intport=DEFEULT_SERVER_PORT;
if(argc>1)
{
port=atoi(argv[1]);
}
if(port<=0||port>0xFFFF)
{
printf("Port(%d)isoutofrange(1-%d)\n",port,0xFFFF);
return;
}
//createepoll///////////////////////
g_epollFd=epoll_create(MAX_EVENTS);
if(g_epollFd<=0)printf("createepollfailed.%d\n",g_epollFd);
//create&bindlistensocket,andaddtoepoll,setnon-blocking
InitListenSocket(g_epollFd,HOST_PORT_TCP,HOST_IP_ADDRESS_TCP);
//eventloop
structepoll_eventevents[MAX_EVENTS];
printf("serverrunning:port[%d]\n",HOST_PORT_TCP);
intcheckPos=0;
/////////////////////////////////
while(1)
{
//waitforeventstohappen
intfds=epoll_wait(g_epollFd,events,MAX_EVENTS,1000);
if(fds<0){
printf("epoll_waiterror,exit\n");
break;
}
for(i=0;i<fds;i++){
structmyevent_s*ev=(structmyevent_s*)events[i].data.ptr;
if((events[i].events&EPOLLIN)&&(ev->events&EPOLLIN))//readevent
{
ev->call_back(ev->fd,events[i].events,ev->arg);
}
if((events[i].events&EPOLLOUT)&&(ev->events&EPOLLOUT))//writeevent
{
ev->call_back(ev->fd,events[i].events,ev->arg);
}
}
}//while
close(connfd);
}
更多相关文章
- 问一个高深的问题,静态html页面如何接收来自服务器的参数?
- golang写服务端程序,作为文件上传与下载的服务器。配合HTML5以网
- Html--树莓派作为Web服务器
- HTML5 Web Sockets与代理服务器交互
- 如何用c#获取服务器端元素的innerhtml(内部有另一个服务器端控件)
- 服务器数据库系列 - 日志系列 - Nginx日志
- MAMP服务器正在运行,但显示“哎呀! Google Chrome无法找到localhos
- Apache服务器压缩和利用浏览缓存问题
- 什么是客户端准备语句?