# 網路程式設計 HW5 ## 1. 連至2個Server * 請寫一個client程式,分別連至Simple TCP/IP Service的Discard與CharGen Server。 * 該Client會將所有接收來自CharGen Server的封包,都送往Discard Server。 * 請持續印出每秒送往Discard Server的Byte數量。 * 有計時 ```c== #include <stdio.h> #include <string.h> #include <stdlib.h> #include <winsock.h> #include <time.h> #define MAXLINE 1024 /* 字串緩衝區長度 */ int main() { SOCKET sd,sd1; /* socket 描述子 */ struct sockaddr_in serv; char str[MAXLINE]; int n; int total; int port; WSADATA wsadata; time_t start,end; /* * 呼叫 WSAStartup() 註冊 WinSock DLL 的使用 */ if (WSAStartup(0x101,(LPWSADATA) &wsadata) != 0) { fprintf(stderr,"echo_srv: WSAStartup() fails!"); exit(1); } /* printf("Echo server IP: "); fgets(str, MAXLINE, stdin); printf("Echo server port: "); scanf("%d",&port); */ strcpy(str,"127.0.0.1"); port = 9; //discard port /* * 填寫 sockaddr_in 結構 (serv) 。 * 內容包括:server 的 IP 位址,port number 等等。 */ serv.sin_family = AF_INET; serv.sin_addr.s_addr = inet_addr(str); serv.sin_port = htons(port); /* * 開啟一個 TCP socket. */ if ( (sd=socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) { fprintf(stderr,"echo_cli: can't open tcp socket\n"); exit(1); } /* * 連接至 echo server */ if ( connect(sd, (LPSOCKADDR) &serv, sizeof(serv)) == SOCKET_ERROR) { fprintf(stderr, "echo_cli: can't connect to echo server\n"); exit(1); } //======================= strcpy(str,"127.0.0.1"); port = 19; //discard port /* * 填寫 sockaddr_in 結構 (serv) 。 * 內容包括:server 的 IP 位址,port number 等等。 */ serv.sin_family = AF_INET; serv.sin_addr.s_addr = inet_addr(str); serv.sin_port = htons(port); /* * 開啟一個 TCP socket. */ if ( (sd1=socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) { fprintf(stderr,"echo_cli: can't open tcp socket\n"); exit(1); } /* * 連接至 echo server */ if ( connect(sd1, (LPSOCKADDR) &serv, sizeof(serv)) == SOCKET_ERROR) { fprintf(stderr, "echo_cli: can't connect to echo server\n"); exit(1); } //======================= start =time(NULL); while( 1) { //Sleep(1000); if ( (n=recv(sd1, str, MAXLINE, 0))==0) { fprintf(stderr,"echo_cli: connection closed\n"); break; } else if (n==SOCKET_ERROR) { fprintf(stderr,"echo_cli: recv() error!\n"); break; } //else printf(str); n = send(sd, str, strlen(str), 0); if ( n == SOCKET_ERROR) { fprintf(stderr, "echo_cli: send() error!\n"); break; } total += n; end =time(NULL); if (difftime(end,start) > 1.0){ printf("send Byte/sec: %d \n",total); total = 0; start = time(NULL); } } /* * 結束 WinSock DLL 的使用 */ closesocket(sd); WSACleanup(); return 0; } ``` ![](https://i.imgur.com/RP5qRvB.png) ## 2. 中繼程式轉送 * 請寫一個中繼程式,模仿代理伺服器( proxy server)提供以下兩個服務 1. datetime服務: 當收到從client傳來字串「time」時,會去詢問Simple TCPIP datetime server的時間,再傳送給client 2. ip查詢dns服務:當收到從client傳來字串「ask://ip位址」時,中繼程式會呼叫gethostbyaddr()查詢後,再將該ip的domain name回覆給client。 * 例如client送出字串:ask://8.8.8.8 ,中繼程式會回覆,而client會收到並印出 dns.google ```cpp== #include <stdio.h> #include <string.h> #include <stdlib.h> #include <winsock.h> #include <string> #include <iostream> #include <sstream> #define MAXLINE 1024 /* 字串緩衝區長度 */ using namespace std; int main() { SOCKET serv_sd, cli_sd,sd; /* socket 描述子 */ struct sockaddr_in serv, cli,dest; int cli_len, n,port; char str[MAXLINE]; WSADATA wsadata; /* * 呼叫 WSAStartup() 註冊 WinSock DLL 的使用 */ if (WSAStartup(0x101,(LPWSADATA) &wsadata) != 0) { fprintf(stderr,"echo_srv: can't use WinSock DLL\n"); exit(1); } // add here // connect to dest strcpy(str,"127.0.0.1"); port = 13; dest.sin_family = AF_INET; dest.sin_addr.s_addr = inet_addr(str); dest.sin_port = htons(port); /* * 開啟一個 TCP socket. */ if ( (sd=socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) { fprintf(stderr,"daytime_cli: can't open tcp socket\n"); exit(1); } /* * 連接至 echo server */ if ( connect(sd, (LPSOCKADDR) &dest, sizeof(dest)) == SOCKET_ERROR) { fprintf(stderr, "daytime_cli: can't connect to echo server\n"); exit(1); } /* * 開啟 TCP socket */ if ( (serv_sd=socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) { fprintf(stderr,"daytime_srv: can't open TCP socket\n"); exit(1); } /* * 指定 socket 的 IP 位址和 port number */ serv.sin_family = AF_INET; serv.sin_addr.s_addr = 0; //serv.sin_port = htons(IPPORT_ECHO); serv.sin_port = htons(7777); // 指定 IPPORT_ECHO 為 echo port if ( bind(serv_sd, (LPSOCKADDR) &serv, sizeof(serv)) <0) { fprintf(stderr, "daytime_srv: can't bind local address\n"); exit(1); } /* * 呼叫 listen() 使 socket 進入「監聽」狀態,並指定 * 最多可同時接受的連接要求(在佇列中) */ if ( listen(serv_sd, 5) < 0) { fprintf(stderr,"daytime_srv: listen() error\n"); exit(1); } /* * 等待 clinet 程式的連接。 * 注意!我們只允許一個 client 程式的連接 */ cli_len=sizeof(cli); while (1) { printf("echo_srv: waiting for client\n"); if ( (cli_sd=accept(serv_sd, (struct sockaddr *) &cli, &cli_len)) == SOCKET_ERROR ) { fprintf(stderr, "echo_srv: accpet() error\n"); closesocket(cli_sd); } else { while (1) { string input=""; while(1) { if ( (n=recv(cli_sd, str, MAXLINE, 0))==0) { fprintf(stderr, "echo_srv: connection closed\n"); break; } else if (n==SOCKET_ERROR) { fprintf(stderr, "echo_srv: recv() error!\n"); break; } if(str[1]=='\n') break; str[n]='\0'; printf("echo_srv from client: %s\n",str); // 顯示從 client 傳來的字串 //add here 2 //send to dest /* if ( send(sd, str, strlen(str), 0) == SOCKET_ERROR) { fprintf(stderr, "echo_srv: connection closed\n"); break; } */ //recv from dest input+=str; } if(input=="time") { if ( (n=recv(sd, str, MAXLINE, 0))==0) { cout<<"123123"<<endl; fprintf(stderr, "echo_srv: connection closed\n"); break; } else if (n==SOCKET_ERROR) { fprintf(stderr, "echo_srv: recv() error!\n"); break; } str[n]='\0'; printf("echo_srv from dest: %s\n",str); // 顯示從 client 傳來的字串 //add complete if ( send(cli_sd, str, strlen(str), 0) == SOCKET_ERROR) { fprintf(stderr, "echo_srv: connection closed\n"); break; } else exit(1); } else { string ipAddress=""; for(unsigned int i=6; i<input.length(); i++) { ipAddress+=input[i]; } char IP[32]; stringstream s1; s1<<ipAddress; s1>>IP; LPHOSTENT hp; struct in_addr sAddr; sAddr.s_addr=inet_addr(IP); cout<<"IP:"<<IP<<'"'<<endl; hp=gethostbyaddr((LPSTR) &sAddr,sizeof(sAddr),AF_INET); if(hp==NULL) { cout<<"NULL"<<endl; exit(1); } else cout<<"host name : "<<hp->h_name<<endl; if(send(cli_sd,hp->h_name,strlen(hp->h_name),0)==SOCKET_ERROR) { cout<<"connection closed"<<endl; break; } else exit(1); } } } } /* * 結束 WinSock DLL 的使用 */ closesocket(cli_sd); closesocket(serv_sd); closesocket(sd); WSACleanup(); return 0; } ``` ![](https://i.imgur.com/A49NLGH.png) ![](https://i.imgur.com/cgBvdGa.png) ## 3. 本週心得 覺得這次作業好難QQ 真的花了很久才寫完,整體來說還是不太懂。 寫作業的時候,也有點毫無頭緒,想說要自己寫,也不知道要寫甚麼,想要從老師的code修改,卻也不知道從何下手,覺得有點受挫QQ 還好有同學幫助,才能完成本次作業(雖然也不知道完成度是如何XD)。 也不太清楚為甚麼IP回傳前面會有很多空格。 ###### tags: `網路程式設計`