项目初衷:
时序图:
目录结构:
代码:
protocol.h
//定义了需要协商的四个协议
#pragma once #pragma pack(1) struct startReq//请求 { char ver;//5 char n_methods;//方法数量 }; struct startRep//回复 { char ver;//5 char method; }; // VER CMD RSV ATYP DST.ADDR DST.PROT // 1 1 X’00’ 1 Variable 2 struct addrReq { char ver; char cmd;//CONNECT:X’01‘ BIND:X’02’ UDP ASSOCIATE:X’03’ char rsv;//保留 char atyp;//后面的地址类型 }; // VER REP RSV ATYP BND.ADDR BND.PORT // 1 1 X’00’ 1 Variable 2 struct addrRep { char ver; char rep; char rsv; char atpy; };
comm.h
服务器端和客户端共同使用的函数,客户端暂未实现
#pragma once #include <iostream> #include <sys/types.h> #include <sys/socket.h> #include <pthread.h> #include <string.h> #include <errno.h> #include <stdio.h> #define SIZE 1024 int recv_data(int sock,void* buf,size_t size); int send_data(int sock,void* buf,size_t size);
comm.cpp
#include "comm.h" using namespace std; int recv_data(int sock,void* buf,size_t len) { char* data_buf=(char*)buf; int ret=0; int size=len; int left=size; while(left){ ret=recv(sock,data_buf+size-left,left,0); if(ret<=0){ return -1; } left-=ret; } return 0; } int send_data(int sock,void* buf,size_t len) { char* data_buf=(char*)buf; int ret=0; int size=len; int left=size; while(left){ int ret=0; ret=send(sock,(char*)buf+size-left,left,0); if(ret<=0){ return -1; } left-=ret; } data_buf[size-left]=‘\0‘; return 0; }
server.cpp
#include <iostream> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <pthread.h> #include <sys/wait.h> #include <netdb.h> #include <stdlib.h> #include "protocol.h" #include "comm.h" #include <assert.h> extern int h_errno; using namespace std; struct ThreadInfo { int in; int out; pthread_t id; }; void proc_handler(int sock); void* thre_handler(void* argc); int main(int argc,char* argv[]) { if(argc!=2){ cout<<"Usage:[proc] [port] "<<endl; return -1; } int listen_sock=socket(AF_INET,SOCK_STREAM,0); if(listen_sock<0){ perror("socket"); } sockaddr_in local; local.sin_family=AF_INET; local.sin_addr.s_addr=INADDR_ANY; //local.sin_addr.s_addr=inet_addr(argv[1]); local.sin_port=ntohs(atoi(argv[1])); socklen_t len=sizeof(local); if(0!=bind(listen_sock,(sockaddr*)&local,len)){ perror("bind"); return -1; } if(0!=listen(listen_sock,5)){ perror("listen"); return -1; } int done=0; while(!done){ sockaddr_in cli_addr; socklen_t len; int sock=accept(listen_sock,(sockaddr*)&cli_addr,&len); cout<<"connection new sock:"<<inet_ntoa(cli_addr.sin_addr)<<endl; pid_t pid1=fork(); if(pid1<0){ perror("fork"); return -1; }else if(pid1>0){ waitpid(pid1,NULL,0); }else{ pid_t pid2=fork(); if(pid2<0){ perror("fork"); return -1; }else if(pid2>0){ return 0; }else{ proc_handler(sock); //close(sock); return 0; } } } return 0; } void proc_handler(int in)//in是和客户端通信的socket { cout<<"proc_handler start..."<<endl; //VER NMETHODS METHODS // 1 1 1 to 255 startReq req; if(0!=recv_data(in,&req,sizeof(req))){ cout<<"recv error in protocol!"<<endl; return; } if(req.ver!=5 || req.n_methods<1){ cout<<"recv error in protocol!"<<endl; return; } //选择methods,八位组0-255 startRep rep; // VER METHOD // 1 1 char methods[256]; if(req.n_methods==1){ if(0!=recv_data(in,methods,1)){ cout<<"recv error in protocol!"<<endl; return; } if(methods[0]==0xFF){//FF没有可接受的方法 return; } else if(methods[0]==0x00){//不需要认证 rep.ver=5; rep.method=0; if(0!=send_data(in,&rep,sizeof(rep))){ cout<<"send error in protocol!"<<endl; return; } }else{ } }else{//选择methods } //接受目标server addr // VER CMD RSV ATYP DST.ADDR DST.PROT // 1 1 X’00’ 1 Variable 2 addrReq reqaddr; if(0!=recv_data(in,&reqaddr,sizeof(reqaddr))){ cout<<"recv error in dstaddr!"<<endl; return; } if(reqaddr.ver!=5 ||reqaddr.rsv!=0){ cout<<"recv error in dstaddr!"<<endl; return; } sockaddr_in remote; remote.sin_family=AF_INET; if(reqaddr.atyp==1){//ipv4 cout<<"accept dst_addr ipv4"<<endl; in_addr_t dstip; if(0!=recv_data(in,&remote.sin_addr.s_addr,4)){ cout<<"recv error in dstaddr!"<<endl; return; } }else if(reqaddr.atyp==3){//域名 cout<<"accept dst_addr domain"<<endl; char domain[SIZE]; if(0!=recv_data(in,&domain,sizeof(domain))){ cout<<"recv error in dstaddr!"<<endl; return; } cout<<"connect to domain: "<<domain<<endl; struct hostent* ht; if((ht=gethostbyname(domain))==NULL){ herror("gethostbyname"); return; } memcpy(&remote.sin_addr.s_addr,ht->h_addr_list[0],sizeof(remote.sin_addr.s_addr));//web服务端可能有多个ip,选择一个 }else{//ipv6 or error return; } //获取目的port if(0!=recv_data(in,&remote.sin_port,2)){ cout<<"recv error in dstport!"<<endl; return; } cout<<"web ip: "<<inet_ntoa(remote.sin_addr)<<" web port: "<<ntohs(remote.sin_port)<<endl; //至此获得客户端想要连接服务器的ip,port // VER REP RSV ATYP BND.ADDR BND.PORT // 1 1 X’00’ 1 Variable 2 addrRep repaddr; repaddr.ver=5; repaddr.rsv=0;//标识为RSV 的字段必须设为X’00’ int out=socket(AF_INET,SOCK_STREAM,0); socklen_t rlen=sizeof(remote); if(0!=connect(out,(sockaddr*)&remote,rlen)){ perror("connect"); repaddr.rep=3;//网络不可达 if(0!=send_data(in,&repaddr,sizeof(repaddr))){ cout<<"error in connect remote!"<<endl; return; } } cout<<"connect success!"<<endl; repaddr.rep=0;//成功 repaddr.atpy=1;//ipv4 if(0!=send_data(in,&repaddr,sizeof(repaddr))){ cout<<"send error to client!"<<endl; return; } struct sockaddr_in local; socklen_t locallen=sizeof(local); if(0!=getsockname(out,(sockaddr*)&local,&locallen)){ perror("getsockname"); return; } cout<<"ip: "<<inet_ntoa(local.sin_addr)<<" port: "<<ntohs(local.sin_port)<<endl; //sleep(5); int len=sizeof(local.sin_addr)+sizeof(local.sin_port); if(0!=send_data(in,&local,len)){ cout<<"send error to client!"<<endl; return; } cout<<"协商完成"<<endl; /////////////////////////////////////////////////////////////////// //至此,完成了协商过程, //以下为正式处理HTTP请求 pthread_t th1,th2; ThreadInfo thInfo1={in,out,th2}; ThreadInfo thInfo2={out,in,th1}; pthread_create(&th1,NULL,thre_handler,&thInfo1); pthread_create(&th2,NULL,thre_handler,&thInfo2); } void* thre_handler(void* argc) { ThreadInfo* info=(ThreadInfo*)argc; int in=info->in; int out=info->out; pthread_t id=info->id; char buf[SIZE*SIZE]; while(1){ int ret=0; ret=recv(in,buf,sizeof(buf),0); if(ret<=0){ perror("recv"); } ret=send(out,buf,ret,0); } close(in); close(out); pthread_cancel(id); return NULL; }
Makefile
.PHONY:all all:server server:server.cpp comm.cpp g++ -o [email protected] $^ -lpthread .PHONY:clean clean: rm -f server
时间: 2024-11-05 14:46:16