# 網路程式設計 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;
}
```

## 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;
}
```


## 3. 本週心得
覺得這次作業好難QQ
真的花了很久才寫完,整體來說還是不太懂。
寫作業的時候,也有點毫無頭緒,想說要自己寫,也不知道要寫甚麼,想要從老師的code修改,卻也不知道從何下手,覺得有點受挫QQ
還好有同學幫助,才能完成本次作業(雖然也不知道完成度是如何XD)。
也不太清楚為甚麼IP回傳前面會有很多空格。
###### tags: `網路程式設計`