http服务器长连接的实现

#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32")

#define I_GET 0x00000001
#define I_POST 0x00000002

typedef struct web_socket
{
SOCKET socket;
struct sockaddr_in client_in;
WSAEVENT event;

char *buffer;
u_long length;

char *data; //post数据
u_long ul_datalength; //post长度

char *httppath; //请求路径
char *pathparam; //请求路径后面的参数

int i_method; //提交方式
bool b_isConnect; //长连接

}web_socket;

unsigned __stdcall thread_client_web(void*);

int main(int argc, char* argv[])
{
WSADATA WSAData;
WSAStartup(MAKEWORD(2,2),&WSAData);

struct sockaddr_in server_in;
SOCKET sock;

server_in.sin_family = AF_INET;
server_in.sin_port = htons(99);
server_in.sin_addr.s_addr = INADDR_ANY;

sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
bind(sock,(struct sockaddr far*)&server_in,sizeof(server_in));

listen(sock,10);

while(true)
{
web_socket *web = (web_socket*)malloc(sizeof(web_socket));
memset(web,0x0,sizeof(web_socket));
int c_len = sizeof(web->client_in);
web->socket = accept(sock,(struct sockaddr far*)&web->client_in,&c_len);

_beginthreadex(NULL,0,thread_client_web,web,0,NULL);

}
printf("Hello World!\n");

WSACleanup();
return 0;
}

char * __stdcall _thread_client_recv_find_header_key_to_string(char *header,char *key,char *outval)
{
char *find,*find_over;
find = strstr(header,key);
if(find == NULL || (find_over = strstr(find,"\r\n")) == NULL )
return NULL;
else
{
find+=strlen(key);
find++;
memcpy(outval,find,find_over-find);
return outval;
}
}

bool __stdcall _thread_client_recv_find_header_key_bool(char *header,char *key,char *val)
{
char outval[32]={0};
if(_thread_client_recv_find_header_key_to_string(header,key,outval)==NULL)
return false;
else
{
if(strstr(outval,val) != NULL)
return true;
else
return false;
}
}

int __stdcall _thread_client_recv_find_header_key_to_integer(char *header,char *key)
{
char val[32]={0};
if(_thread_client_recv_find_header_key_to_string(header,key,val)==NULL)
return 0;
else
return atoi(val);
}

bool __stdcall _thread_client_recv_post_http_header(web_socket *web)
{
char *t_find=NULL;
if(memcmp(web->buffer,"GET",3)==0)
{
web->i_method = I_GET;
web->httppath = strstr(web->buffer,"GET ");
web->httppath+=strlen("GET ");
}
else if(memcmp(web->buffer,"POST",4)==0)
{
web->i_method = I_POST;
web->httppath = strstr(web->buffer,"POST ");
web->httppath+=strlen("POST ");

web->data+=2;
*web->data = '\0';
web->data = web->data+2;
web->ul_datalength = _thread_client_recv_find_header_key_to_integer(web->buffer,"Content-Length");
}

web->b_isConnect = _thread_client_recv_find_header_key_bool(web->buffer,"Connection","keep-alive");

if(web->httppath == NULL)
return false;
t_find = strstr(web->httppath," ");
if(t_find != NULL)
{
*t_find = '\0';
}
t_find = strstr(web->httppath,"?");
if(t_find != NULL)
{
*t_find = '\0';
web->pathparam = t_find+1;
}
return true;
}

bool __stdcall _thread_client_check_is_recv(web_socket *web)
{
if(web->i_method == 0 )
{
web->data = strstr(web->buffer,"\r\n\r\n");
if(NULL == web->data)
return true;
else
_thread_client_recv_post_http_header(web);
}
if(web->i_method == I_GET)
{
return false;
}
else if(web->i_method == I_POST)
{
if(web->ul_datalength == strlen(web->data))
return false;
}
return true;
}

unsigned __stdcall thread_client_web_send(web_socket *web)
{
if(web->i_method == I_GET)
printf("RECV:%d\n%s:%s\n",web->length,web->httppath,web->pathparam);
else if(web->i_method == I_POST)
printf("RECV:%d\n%s:%s\n%s\n",web->length,web->httppath,web->pathparam,web->data);
char t[]="aaaaa";
char buff[512]={0};

sprintf(buff,"http/1.0 200 ok\r\nContent-Length:%d\r\nConnection:Keep-Alive\r\n\r\n%s",strlen(t),t);

send(web->socket,buff,strlen(buff),0);
return 1;
}

unsigned __stdcall thread_client_web(void* param)
{
#define PAGE_SIZE 0x2000

bool isRecvOver;
web_socket *web = (web_socket*)param;
web->event = WSACreateEvent();
web->buffer = (char*)malloc(PAGE_SIZE*10);

WSAEventSelect(web->socket,web->event,FD_READ|FD_CLOSE);

WSANETWORKEVENTS networkevent;
u_long cRecv;

web_loop_next:
isRecvOver=true;

memset(web->buffer,0x0,PAGE_SIZE*10);
web->length=0;
web->b_isConnect = true;
web->i_method=0;
web->data=NULL;
web->httppath=NULL;
web->pathparam=NULL;

while(isRecvOver)
{
WaitForSingleObject(web->event,INFINITE);

WSAEnumNetworkEvents(web->socket,web->event,&networkevent);
if(networkevent.lNetworkEvents & FD_READ)
{
ioctlsocket(web->socket,FIONREAD,&cRecv);
web->length += recv(web->socket,web->buffer+web->length,cRecv,0);
isRecvOver = _thread_client_check_is_recv(web);
}
else if(networkevent.lNetworkEvents & FD_CLOSE)
{
closesocket(web->socket);
isRecvOver=false;
web->b_isConnect=false;
goto _exit;
}
}

thread_client_web_send(web);

// if(web->b_isConnect)
goto web_loop_next;

_exit:
printf("over");

free(web->buffer);
free(web);
return 0;
}

出处:http://blog.csdn.net/trojanth/archive/2008/12/28/3630821.aspx