---
# System prepended metadata

title: 網路程式設計 HW5
tags: [網路程式設計]

---

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