【windows socket+HTTP服务器客户端】

Windows Socket+HTTP服务器客户端


      Winsock 是 Windows下套接字标准
        
       1.HTTP协议

         HTTP是基于客户端/服务器的请求,响应协议。

       请求:由客户端向服务器发起,指定了要从服务器获取的资源。请求包含了协议首部,指明了客户端处理能力信息,如可以处理的文件类型,支持的语言,编码方式等。
       响应:服务器收到客户端的请求后,解析这个请求,构造响应,并发送给客户端。响应同样包含了协议首部,指明了服务器的相关信息。
         
       2.简易HTTP服务器与客户端

        实际中的HTTP协议,考虑到多种需求,协议具有一定的复杂性,这里我们只实现一个简单的HTTP服务器与客户端,重在理解HTTP协议的工作原理。
         Winsock编程下,客户端通过socket向客户端发送一段数据(即请求),这段数据包含了客户端请求的资源(即文件)。
        客户端收到这段数据后,对这段数据进行处理(即解析URL),提取客户端请求的资源名,根据资源名找到服务器资源,将资源与其他信息处理后(即响应)发送给客户端。
         
       3.HTTP服务器与客户端实质

        HTTP协议是建立在socket之上的,本质上是两个程序通过socket相互发送数据。HTTP协议,规定了发送方发送数据的格式以及接受方如何使用接受的数据。实现HTTP服务器与客户端,HTTP协议的实现体现在双发对发送与接受数据的处理上。最简单的例子,客户端向服务器发送一个"GET 1.html"数据,服务器收到数据后,解读"GET 1.html",明白客户端想得(GET)到1.html文件,服务器将1.html文件的内容发送给客户端,客户端接收到含1.html文件内容的数据后,新建1.html文件并写入服务器端发送来的数据。

         4.牛刀小试
         先在VC6.0中运行服务器,再打开一个VC6.0运行客户端。


         运行效果:
          常用的浏览器也是客户端,显然我们的客户端只是简单的将html文件内容打印,浏览器则会按HTML规则处理html文件然后显示。

服务器与客户端参考了《Winsock网络编程经络》
客户端程序:
#include
    
    
     
     
#include
     
     
      
      
#pragma comment(lib,"ws2_32.lib")

char *http_req_hdr_tmp1="GET %s HTTP/1.1\r\n"
                        "Accept:image/gif,image/jpeg,*/*\r\nAccept-language:zh-ch\r\n"
						"Accept-Encoding:gzip,deflate\r\nHost:%s:%d\r\n"
						"Uert-Agent:Jiangwei's Browser<0.1>\r\nConnection:keep-Alive\r\n\r\n";

void http_pares_request_url(char *buf,char *host,
							int *port,char *file_name)
{
	int length=0;
	char port_buf[8];
	char *buf_end=(char *)(buf+strlen(buf));
	char *begin,*host_end,*colon,*file;

    //寻找主机开始位置
	begin = strstr(buf,"//");
	begin = (begin ? begin+2:buf);

	colon = strchr(begin,':');
	host_end = strchr(begin,'/');

	if(host_end == NULL)
	{
		host_end = buf_end;	
	}
	else
	{
		//得到文件名
		file = strrchr(host_end,'/');
		if(file && (file+1)!=buf_end)
		{
			strcpy(file_name,file+1);
		}
	}

	if(colon)
	{
		//得到端口号
		colon++;
		length = host_end-colon;
		memcpy(port_buf,colon,length);
		port_buf[length]=0;
		*port = atoi(port_buf);

		host_end = colon -1;
	}

	//得到主机
	length = host_end-begin;
	memcpy(host,begin,length);
	host[length]=0;
}

int main()
{
	WSADATA wsa;
	WSAStartup(MAKEWORD(2,0),&wsa);

	SOCKET http_sock;
	SOCKADDR_IN serveraddr;
	struct hostent *host_ent;

	int result;
	int Send_len;
	char data_buf[1024];
	char host[256]="127.0.0.1";
	int port=8080;
	unsigned long addr;
	char file_name[256]="index.html";
	FILE *file_web;
    
	/*input为URL
	 5.html为请求的文件
	 此时服务器程序文件夹下要要有5.html
	*/
	char *input="http://127.0.0.1:8080/5.html";
	http_pares_request_url(input,host,&port,file_name);
    
	//判断地址是否可用
	addr=inet_addr(host);
	if(addr==INADDR_NONE)
	{
		host_ent=gethostbyname(host);
		if(!host_ent)
		{
			printf("服务器不可用!\n");
			return -1;
		}
		memcpy(&addr,host_ent->h_addr_list[0],host_ent->h_length);
	}
    
	//根据输入的地址信息,初始化IP,Port
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(port);
	serveraddr.sin_addr.s_addr = addr;
    
	//创建服务器socket
	http_sock = socket(AF_INET,SOCK_STREAM,0);
    
	//请求连接服务器socket
	result = connect(http_sock,(SOCKADDR *)&serveraddr,sizeof(serveraddr));
	if(result==SOCKET_ERROR)
	{
		closesocket(http_sock);
		printf("[Web]连接失败!");
		return -1;
	}
    
    //发送http请求
	Send_len=sprintf(data_buf,http_req_hdr_tmp1,input,host,port);
	result=send(http_sock,data_buf,Send_len,0);
	if(result==SOCKET_ERROR)
	{
		printf("[Web]发送失败!\n");
		return -1;
	}

	file_web=fopen(file_name,"w+");

	//循环接收服务器发来的数据
	do
	{
		result = recv(http_sock,data_buf,1024,0);
		if(result > 0)
		{
			//将接收的数据写入文件
			fwrite(data_buf,1,result,file_web);
			//打印接收的数据
			data_buf[result]=0;
			printf("%s",data_buf);
		}
	}while(result>0);
	
	//关闭文件
	fclose(file_web);
	//关闭套接字
	closesocket(http_sock);
	WSACleanup();

	return 0;
}

     
     
    
    
服务器程序:
#include
     
     
      
      
#include
      
      
       
       
#pragma comment(lib,"ws2_32.lib")

//定义文件类型对应的content-tyoe
struct doc_type{
	char *suffix;
	char *type;
};

//文件
struct doc_type file_type[]=
{
	{"html",  "text/html"},
	{"gif",   "imag/gif"},
	{"jpeg",  "imag/jpeg"},
	{NULL,    NULL}
};

//响应首部内容
char *http_res_hdr_tmp1="HTTP/1.1 200 OK \r\nServer:Jiangwei's Server<0.1>\r\n"
                        "Accept-Ranges:bytes\r\nContent-Length:%d\r\nConnection:close\r\n"
						"Content-Type:%s\r\n\r\n";

//通过后缀,查找到对应的content-type
char *http_get_type_by_suffix(const char *suffix)
{
	struct doc_type *type;
	for(type=file_type;type->suffix;type++)
	{
		if(strcmp(type->suffix,suffix)==0)
			return type->type;
	}
	return NULL;
}


//解析客户端发送过来的请求
void http_parse_request_cmd(char *buf,int buflen,char *file_name,char *suffix)
{
	int length=0;
	char *begin,*end,*bias;

	//查找URL开始位置
	begin=strchr(buf,' ');
	begin++;
    
	//查找URL结束位置
	end=strchr(begin,' ');
	*end=0;
    
	bias=strrchr(begin,'/');
	length=end-bias;

	//找到文件名开始的位置
	if((*bias=='/')||(*bias=='\\'))
	{
		bias++;
		length--;
	}

	//得到客户端请求的文件名
	if(length>0)
	{
		memcpy(file_name,bias,length);
		file_name[length]=0;

		begin = strchr(file_name,'.');
		if(begin)
			strcpy(suffix,begin+1);
	}
}

int http_send_response(SOCKET soc,char *buf,int buf_len)
{
	int read_len,file_len,hdr_len,send_len;
	char *type;
	char read_buf[1024];
	char http_header[1024];
	char file_name[256]="index.html";
	char suffix[16]="html";
	FILE *res_file;

	//通过解析URL,得到文件名
	http_parse_request_cmd(buf,buf_len,file_name,suffix);

	//打开文件
	res_file=fopen(file_name,"rb+");

	if(res_file==NULL)
	{
		printf("[Web]文件:%s 不存在!\n",file_name);
		return 0;
	}

	//计算文件大小
	fseek(res_file,0,SEEK_END);
	file_len=ftell(res_file);
	fseek(res_file,0,SEEK_SET);

	//获得文件content-type
	type=http_get_type_by_suffix(suffix);
    
	if(type==NULL)
	{
		printf("[Web]没有相关的文件类型!\n");
		return 0;
	}
    
	//构造响应首部,加入文件长度,content-type信息
	hdr_len=sprintf(http_header,http_res_hdr_tmp1,file_len,type);
	send_len=send(soc,http_header,hdr_len,0);
	
	if(send_len==SOCKET_ERROR)
	{
		fclose(res_file);
		printf("[Web]发送失败,错误:%d\n",WSAGetLastError());
		return 0;
	}

	//发送文件
	do
	{
		read_len=fread(read_buf,sizeof(char),1024,res_file);
		if(read_len>0)
		{
			send_len=send(soc,read_buf,read_len,0);
			file_len-=read_len;
		}
	}while((read_len>0) && (file_len>0));
	fclose(res_file);
    return 1;
}
int main(){
	WSADATA wsa;
	WSAStartup(MAKEWORD(2,0),&wsa);
	SOCKET serversoc,acceptsoc;
	SOCKADDR_IN serveraddr;
	SOCKADDR_IN fromaddr;
	char Recv_buf[1024];
	int from_len=sizeof(fromaddr);
	int result;
	int Recv_len;

	//创建socket
	serversoc = socket(AF_INET,SOCK_STREAM,0);
	if(serversoc==INVALID_SOCKET)
    {
		printf("[Web]创建套接字失败!");
		return -1;
	}

	//初始化服务器IP,Port
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(8080);
	serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);

	//绑定socket
	result=bind(serversoc,(SOCKADDR *)&serveraddr,sizeof(serveraddr));
	if(result==SOCKET_ERROR)
	{
		closesocket(serversoc);
		printf("[Web]绑定套接字失败!");
		return -1;
	}
    
	//监听socket请求
	result = listen(serversoc,3);
	printf("[Web]服务器正在运行.....\n");

	while(1)
	{
		//接收请求
		acceptsoc = accept(serversoc,(SOCKADDR *)&fromaddr,&from_len);
		if(acceptsoc==INVALID_SOCKET)
		{
			printf("[Web]接收请求失败!");
			break;
		}
		printf("[Web]连接来自 IP:  %s  Port:  %d  \n",inet_ntoa(fromaddr.sin_addr),ntohs(fromaddr.sin_port));
		
		//接收来自客户端的请求
        Recv_len=recv(acceptsoc,Recv_buf,1024,0);
		if(Recv_len==SOCKET_ERROR)
		{
			printf("[Web]接收数据失败!");
			break;
		}
		Recv_buf[Recv_len]=0;
		//向客户端发送响应数据
		result = http_send_response(acceptsoc,Recv_buf,Recv_len);

		closesocket(acceptsoc);
	}

	closesocket(serversoc);
	WSACleanup();

	return 0;
}

      
      
     
     


  • 7
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值