---
# System prepended metadata

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

---

# 網路程式設計 HW8
* 攔阻模式
    函示呼叫後，需要完成才回覆。(API等完成後才回覆)
* 非攔阻模式
    * API立即回覆，不需要等到完成後才回覆。
    * 代價:
        * 回覆!=完成
        * 須不斷檢查才能確認完成。
    * 報酬:
        不會被卡住，等待期間可以做其他事情。
* 攔阻模式優缺點
    |   優點    |             缺點             |
    |:---------:|:--------------------------:|
    | 流程簡單    |   函式攔阻後無法進行其他動作   |
    | 容易debug |           功能受限           |
    | 流程簡單  |             --             |
* NB程式
    * 使用API:ioctlsocket()
    * 改變socket模式
        * 放置需要改變模式之前(recv()、accept())
        * 攔阻模式 : iMode=0
        * 非攔阻模式 : iMode=1

## 應用1 聊天室第1版解除一人一句的限制
* 非攔阻模式
    * server 
        一直接收，每隔5秒才回傳I know
    * client
        用不同間隔，server總是5秒才回應
* 畫面
    ![](https://i.imgur.com/vtd68Na.png)
:::spoiler
* Client
    ```cpp==
    // simple TCP chat client

    #include <stdio.h>
    #include <winsock.h>

    int main(){
        SOCKET sd;
        WSADATA wsadata;
        struct sockaddr_in serv;
        int i,n;
        char str[100]="I love NP!";

        WSAStartup(0x101,&wsadata);
        sd = socket(AF_INET, SOCK_STREAM, 0);

        serv.sin_family = AF_INET;
        serv.sin_port = htons(1234);
        serv.sin_addr.s_addr = inet_addr("127.0.0.1");

        connect(sd, (struct sockaddr *)  &serv,sizeof(serv) );
        printf("Connect to server.\n");


        u_long iMode=1; // set NB mode
        ioctlsocket(sd,FIONBIO,&iMode);

        while(1){
            strcpy(str,"I miss you!");
            printf("(clietn): %s\n",str);

            send(sd,str, strlen(str)+1,0);

            Sleep(500);

            memset(str,0,100);
            n = recv(sd,str, 100, 0);
            if(n>0)
            {
                str[n]='\0';
                printf("(server): %s\n",str);
            }
        }
        closesocket(sd);
        WSACleanup();

    }
    ```
* Server
```cpp==

// simple TCP chatroom server

#include <stdio.h>
#include <winsock.h>
#include <time.h>

int main(){
	SOCKET sd,clnt_sd;
	WSADATA wsadata;
	struct sockaddr_in serv,clnt;
	int i,n;
	char str[100];

	WSAStartup(0x101,&wsadata);
	sd = socket(AF_INET, SOCK_STREAM, 0);
	serv.sin_family = AF_INET;
	serv.sin_port = htons(1234);
	serv.sin_addr.s_addr = inet_addr("127.0.0.1");

	bind(sd, (struct sockaddr *) &serv, sizeof(serv));

	listen(sd,5);
	int clnt_len=sizeof(clnt);
	printf("Server waits.\n");
	clnt_sd =  accept(sd, (struct sockaddr *)  &clnt,&clnt_len );
	printf("Client is connected.\n");

	u_long iMode=1;
	ioctlsocket(clnt_sd,FIONBIO,&iMode);

	clock_t t2=0;
	clock_t t1=0;
	float time;
	while(1){
		n = recv(clnt_sd,str, 100, 0);
		if(n>0)
        {
            str[n]='\0';
            printf("(client): %s\n",str);
        }

        t1=clock();
        time=(t1-t2)/CLOCKS_PER_SEC;

        if(time>5)   //5秒
        {
            strcpy(str,"I know.");
            printf("(server): %s\n",str);
            send(clnt_sd,str, strlen(str)+1,0);
            t2=clock();
            Sleep(800);
        }

	}
	closesocket(sd);
	closesocket(clnt_sd);
	WSACleanup();

}

```
:::
## 應用2 聊天室第2版解除一人一句限制
* lient執行後，先輸入名稱與時間間隔
    * 之後便固定週期發送出其名稱。
* server先等5秒待雙方都連入後
    * 接著不管順序，收到誰的都轉送給另一方
* client程式只有一個
    * 不分client1,client2。
* 由於client/server雙方都有接收，
    * 都須將socket改為非攔阻模式。
* 畫面
    ![](https://i.imgur.com/5GaifSo.png)
:::spoiler
* Client
```cpp==
// simple TCP chat client(1)
// v2: two client chat through server

#include <stdio.h>
#include <winsock.h>
#include <time.h>
int main(){
	SOCKET sd;
	WSADATA wsadata;
	struct sockaddr_in serv;
	int i,n;
	char str[100];
	char str1[100];

	WSAStartup(0x101,&wsadata);
	sd = socket(AF_INET, SOCK_STREAM, 0);

	serv.sin_family = AF_INET;
	serv.sin_port = htons(1234);
	serv.sin_addr.s_addr = inet_addr("127.0.0.1");

	connect(sd, (struct sockaddr *)  &serv,sizeof(serv) );
	printf("Connect to server.\n");

	u_long iMode=1; // set NB mode
	ioctlsocket(sd,FIONBIO,&iMode);

	printf("Client Name : "); //名稱
	gets(str1);
	printf("Time Interval(sec) : "); //時間間隔
	int ti;
	scanf("%d",&ti);
	Sleep(5000); 

	clock_t t1,t2=0;
	float time;

	while(1){

        t1=clock();
        time=(t1-t2)/CLOCKS_PER_SEC;
        if(time>ti)
        {
            strcpy(str,str1);
            printf("[Client]: %s\n",str);
            send(sd,str,strlen(str),0);
            t2=clock();
        }
		memset(str,0,100);
		n=recv(sd,str, 100, 0);
		if(n>0)
        {
            str[n]='\0';
            printf("[Other]:%s\n",str);
        }
        Sleep(100);
	}
	closesocket(sd);
	WSACleanup();

}
```
* Server
```cpp==
#include <stdio.h>
#include <winsock.h>

int main(){
	SOCKET sd,clnt_sd1,clnt_sd2;
	WSADATA wsadata;
	struct sockaddr_in serv,clnt1,clnt2;
	int i,n;
	char str[100];

	WSAStartup(0x101,&wsadata);
	sd = socket(AF_INET, SOCK_STREAM, 0);
	serv.sin_family = AF_INET;
	serv.sin_port = htons(1234);
	serv.sin_addr.s_addr = inet_addr("127.0.0.1");

	bind(sd, (struct sockaddr *) &serv, sizeof(serv));

	listen(sd,5);
	int clnt_len1=sizeof(clnt1);
	int clnt_len2=sizeof(clnt2);
	printf("Server waits.\n");
	clnt_sd1 =  accept(sd, (struct sockaddr *)  &clnt1,&clnt_len1 );
	printf("One client connects.\n");
	clnt_sd2 =  accept(sd, (struct sockaddr *)  &clnt2,&clnt_len2 );
	printf("Two clients connect.\n");

	u_long iMode=1;
	ioctlsocket(clnt_sd1,FIONBIO,&iMode);
    ioctlsocket(clnt_sd2,FIONBIO,&iMode);

	while(1){
        //收到(1)
		n = recv(clnt_sd1,str, 100, 0);
		if(n>0)
        {
            str[n]='\0';
            printf("(1): %s\n",str);
            send(clnt_sd2,str,strlen(str)+1,0);
        }
        //收到(2)
		n = recv(clnt_sd2,str, 100, 0);
		if (n > 0 )
        {
            str[n]='\0';
            printf("(2): %s\n",str);
            send(clnt_sd1,str, strlen(str)+1,0);
        }
        Sleep(100);
	}
	closesocket(sd);
	closesocket(clnt_sd1);
	closesocket(clnt_sd2);
	WSACleanup();

}

```
:::

## 應用3 server可服務多個client 且 client可陸續連入
* client可隨時連入，並開始接收文字
* server可最多服務5個client
> 專注於server的非攔阻部分，client可維持攔阻模式
 * 畫面
     * 一個登入
         ![](https://i.imgur.com/7Yo92Qi.png)
    * 兩個登入
        ![](https://i.imgur.com/wr5uRBx.png)
    * 三個登入
        ![](https://i.imgur.com/prTC3ul.png)
    * 四個登入
        ![](https://i.imgur.com/zkFUcZv.png)
    * 五個登入
        ![](https://i.imgur.com/tDpPo7h.png)
:::spoiler
* Client
```cpp==
// simple TCP chat client

#include <stdio.h>
#include <winsock.h>

int main(){
	SOCKET sd;
	WSADATA wsadata;
	struct sockaddr_in serv;
	int i,n;
	char str[100]="I love NP!";

	WSAStartup(0x101,&wsadata);
	sd = socket(AF_INET, SOCK_STREAM, 0);

	serv.sin_family = AF_INET;
	serv.sin_port = htons(1234);
	serv.sin_addr.s_addr = inet_addr("127.0.0.1");

	connect(sd, (struct sockaddr *)  &serv,sizeof(serv) );
	printf("Connect to server.\n");

	while(1){
        n = recv(sd,str, 100, 0);
        if(n <= 0) break;
        printf("Recv: %s\n",str);
	}
	closesocket(sd);
	WSACleanup();

}

```
* Server
```cpp==
// simple TCP chatroom server
// v1:one clint chat to server

#include <stdio.h>
#include <winsock.h>

int main(){
	SOCKET sd,clnt_sd[5];
	WSADATA wsadata;
	struct sockaddr_in serv,clnt;
	int i,n;
	char str[100]="I love NP!";

	WSAStartup(0x101,&wsadata);
	sd = socket(AF_INET, SOCK_STREAM, 0);
	serv.sin_family = AF_INET;
	serv.sin_port = htons(1234);
	serv.sin_addr.s_addr = inet_addr("127.0.0.1");

	bind(sd, (struct sockaddr *) &serv, sizeof(serv));

	listen(sd,5);
	u_long iMode=1;
	ioctlsocket(sd,FIONBIO,&iMode);

	int clnt_len=sizeof(clnt);
	printf("Server waits.\n");

	for(int i=0;i<5;i++)
    {
        clnt_sd[i]=-1;
    }

    int curr_client_num=0;

	while(1){
        n=accept(sd,(struct sockaddr*) &clnt,&clnt_len);
        if(n!=-1)
        {
            clnt_sd[curr_client_num]=n;
            printf("Client[%d] is connected.\n",curr_client_num);
            curr_client_num++;
        }

		for(int i=0;i<5;i++)
        {
            if(clnt_sd[i]!=-1)
            {
                send(clnt_sd[i],str,strlen(str)+1,0);
                printf("Send to clnt_sd[%d]: %s\n",i,str);
            }
        }
        Sleep(1000);
	}
	closesocket(sd);
	for(int i=0;i<5;i++)
    {
        closesocket(clnt_sd[i]);
    }

	WSACleanup();
	system("pause");

}

```
:::
## 心得
覺得這次作業很酷，有些剛好是我之前有想過是不是都可以做的，但都還沒實際操作過，這次剛好有老師解惑且有機會可以實作看看。
###### tags: `網路程式設計`