網路程式設計 hw8

觀念題

第一題

  • 請說明,當socket設定blocking mode與non-blocking mode之後,會有何差異?
    • 在攔阻模式下
      • recv()函數會等待資料收到才會進到下一行
      • accept()函數會等待客戶連線才會進到下一行
    • 在非攔阻模式下
      • recv()函數不會等待收到資料,當沒收到,會回傳-1
      • accept()函數不會等待客戶連線,當沒連線,會回傳-1
      • 感覺上非攔阻模式就像急性子
  • 請說明,影片裏第一個程式的範例裏,由blocking mode改為non-blocking mode,請問結果有何不同?
    • 以下為執行結果
      • blocking mode
        image
      • non-blocking mode
        image
    • 差別
      • blocking mode
        • 在blocking mode下,recv會一直等待,直到接收到資料
      • non-blocking mode
        • 在non-blocking mode,recv不會等待,沒收到就直接回傳-1

實作題

第二題

  • TCP或UDP都可改為非攔阻,請將上例中non-blocking mode的client與server,由TCP改為UDP。
  • 程式碼
    • Sever
      C
      ​​​​​​​​#include <stdio.h> ​​​​​​​​#include <string.h> ​​​​​​​​#include <winsock.h> ​​​​​​​​#define MAXLINE 1024 /* 字串緩衝區長度 */ ​​​​​​​​int main() ​​​​​​​​{ ​​​​​​​​ SOCKET serv_sd, cli_sd; /* socket 描述子 */ ​​​​​​​​ int cli_len, n,i; ​​​​​​​​ char str[MAXLINE]; ​​​​​​​​ struct sockaddr_in serv, cli; ​​​​​​​​ WSADATA wsadata; ​​​​​​​​ WSAStartup(0x101, &wsadata); //呼叫 WSAStartup() 註冊 WinSock DLL 的使用 ​​​​​​​​ serv_sd=socket(AF_INET, SOCK_DGRAM, 0);// 開啟 UDP socket ​​​​​​​​ //指定 socket 的 IP 位址和 port number ​​​​​​​​ serv.sin_family = AF_INET; ​​​​​​​​ serv.sin_addr.s_addr = 0; ​​​​​​​​ serv.sin_port = htons(5678); // 指定 IPPORT_ECHO 為 echo port ​​​​​​​​ bind(serv_sd, (LPSOCKADDR) &serv, sizeof(serv)); ​​​​​​​​ cli_len = sizeof(cli); ​​​​​​​​ u_long iMode=1; ​​​​​​​​ ioctlsocket(serv_sd,FIONBIO,&iMode); ​​​​​​​​ while (1) { ​​​​​​​​ n=recvfrom(serv_sd, str, MAXLINE, 0, (LPSOCKADDR) &cli, &cli_len); ​​​​​​​​ str[n]='\0'; ​​​​​​​​ if (n > 0 ) ​​​​​​​​ printf("Recv: %s\n",str); // 顯示從 client 傳來的字串 ​​​​​​​​ Sleep(1000); ​​​​​​​​ int nError=WSAGetLastError(); ​​​​​​​​ if(nError!=WSAEWOULDBLOCK && nError!=0){ ​​​​​​​​ printf("Disconnected! error code:%d\n",nError); ​​​​​​​​ closesocket(cli_sd); ​​​​​​​​ break; ​​​​​​​​ } ​​​​​​​​ } ​​​​​​​​ //結束 WinSock DLL 的使用 ​​​​​​​​ closesocket(serv_sd); ​​​​​​​​ closesocket(cli_sd); ​​​​​​​​ WSACleanup(); ​​​​​​​​}
      Python
      ​​​​​​​​import socket ​​​​​​​​import time ​​​​​​​​""" ​​​​​​​​ Server Information ​​​​​​​​ IP: 127.0.0.1 ​​​​​​​​ PORT: 1234 ​​​​​​​​""" ​​​​​​​​IP, PORT = "127.0.0.1", 1234 ​​​​​​​​# create UDP socket ​​​​​​​​server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) ​​​​​​​​server.bind((IP, PORT)) ​​​​​​​​server.setblocking(False) ​​​​​​​​while True: ​​​​​​​​ try: ​​​​​​​​ data, addr = server.recvfrom(1024) ​​​​​​​​ print(f"Received: {data.decode()} from {addr}") ​​​​​​​​ except: ​​​​​​​​pass
    • Client
      C
      ​​​​​​​​#include <stdio.h> ​​​​​​​​#include <string.h> ​​​​​​​​#include <winsock.h> ​​​​​​​​#define MAXLINE 1024 ​​​​​​​​int main(int argc, char** argv) { ​​​​​​​​ SOCKET sd; ​​​​​​​​ struct sockaddr_in serv; ​​​​​​​​ char str[1024]="How are you?",str1[1024]; ​​​​​​​​ WSADATA wsadata; ​​​​​​​​ int n,i; ​​​​​​​​ WSAStartup(0x101,(LPWSADATA) &wsadata); // 呼叫 WSAStartup() 註冊 WinSock DLL 的使用 ​​​​​​​​ sd=socket(AF_INET, SOCK_DGRAM, 0); //開啟一個 UDP socket. ​​​​​​​​ serv.sin_family = AF_INET; ​​​​​​​​ serv.sin_addr.s_addr = inet_addr("127.0.0.1"); ​​​​​​​​ serv.sin_port = htons(5678); ​​​​​​​​ connect(sd, (LPSOCKADDR) &serv, sizeof(serv)); // 連接至 echo server ​​​​​​​​ printf("Client has connectted to Server.\n"); ​​​​​​​​ printf("Waiting 10 secs on purpose...\n"); ​​​​​​​​ Sleep(10000); // 建立連線後,刻意停頓, 觀察 recv()是否block ​​​​​​​​ for (;;){ //每隔3秒,週期送出 ​​​​​​​​ Sleep(3000); ​​​​​​​​ send(sd, str, strlen(str)+1, 0); ​​​​​​​​ int nError=WSAGetLastError(); ​​​​​​​​ if(nError!=WSAEWOULDBLOCK && nError!=0) ​​​​​​​​ { ​​​​​​​​ printf("Winsock error code:%d\n",nError); ​​​​​​​​ printf("Disconnected!"); ​​​​​​​​ // Close our socket entirely ​​​​​​​​ closesocket(sd); ​​​​​​​​ break; ​​​​​​​​ } ​​​​​​​​ printf("Send every 3 secs: %s\n" ,str); ​​​​​​​​} ​​​​​​​​ closesocket(sd); //關閉TCP socket ​​​​​​​​ WSACleanup(); // 結束 WinSock DLL 的使用 ​​​​​​​​ return 0; ​​​​​​​​}
      Python
      ​​​​​​​​import socket ​​​​​​​​import time ​​​​​​​​""" ​​​​​​​​ Server Information ​​​​​​​​ IP: 127.0.0.1 ​​​​​​​​ PORT: 1234 ​​​​​​​​""" ​​​​​​​​IP, PORT = "127.0.0.1", 1234 ​​​​​​​​# create UDP socket ​​​​​​​​sd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) ​​​​​​​​sd.connect((IP, PORT)) ​​​​​​​​sd.setblocking(False) ​​​​​​​​print("Wait for 10 secs...") ​​​​​​​​time.sleep(10) ​​​​​​​​while True: ​​​​​​​​ try: ​​​​​​​​ sd.send(b"Hello World!") ​​​​​​​​ print("Send every 3 secs: Hello World!") ​​​​​​​​ time.sleep(3) ​​​​​​​​ except: ​​​​​​​​ pass
  • 執行結果
    image
  • 備註
    • 在Python中非阻攔模式需要用try/except
      ​​​​​​​​try: 
      ​​​​​​​​    sd.resv()
      ​​​​​​​​except:
      ​​​​​​​​    pass
      

第三題

  • 程式碼
    • Sever
      C
      ​​​​​​​​#include <stdio.h> ​​​​​​​​#include <winsock.h> ​​​​​​​​int main(){ ​​​​​​​​ FILE *fin, *fout; ​​​​​​​​ fin = fopen("def.txt", "r"); ​​​​​​​​ fout = fopen("server.txt","w"); ​​​​​​​​ SOCKET sd,clnt_sd; ​​​​​​​​ WSADATA wsadata; ​​​​​​​​ struct sockaddr_in serv,clnt; ​​​​​​​​ int i,n; ​​​​​​​​ char str[2048]=""; ​​​​​​​​ 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 mode = 1; ​​​​​​​​ ioctlsocket(clnt_sd,FIONBIO,&mode); ​​​​​​​​ while(1){ ​​​​​​​​ char* c_line = NULL; ​​​​​​​​ size_t len = 0; ​​​​​​​​ int status = getline(&c_line,&len,fin); ​​​​​​​​ if (status != EOF) { ​​​​​​​​ send(clnt_sd,c_line, strlen(c_line)+1,0); ​​​​​​​​ printf("Send: %s\n",c_line); ​​​​​​​​ } ​​​​​​​​ else{ ​​​​​​​​ send(clnt_sd,"END", 4,0); ​​​​​​​​ printf("Send: END\n"); ​​​​​​​​ } ​​​​​​​​ free(c_line); ​​​​​​​​ memset(str,0,sizeof(str)); ​​​​​​​​ n = recv(clnt_sd,str, sizeof(str), 0); ​​​​​​​​ if (n > 0){ ​​​​​​​​ str[n] = '\0'; ​​​​​​​​ printf("Receive: %s\n",str); ​​​​​​​​ if (strcmp(str, "END\0") == 0 && status == EOF) { ​​​​​​​​ break; ​​​​​​​​ } ​​​​​​​​ else if (strcmp(str, "END\0") == 0) { ​​​​​​​​ continue; ​​​​​​​​ } ​​​​​​​​ fprintf(fout,"%s",str); ​​​​​​​​ } ​​​​​​​​ else if (n == 0){ ​​​​​​​​ break; ​​​​​​​​ } ​​​​​​​​ Sleep(100); ​​​​​​​​ } ​​​​​​​​ closesocket(sd); ​​​​​​​​ closesocket(clnt_sd); ​​​​​​​​ fclose(fin); ​​​​​​​​ fclose(fout); ​​​​​​​​ WSACleanup(); ​​​​​​​​}
      Python
      ​​​​​​​​import socket ​​​​​​​​import time ​​​​​​​​""" ​​​​​​​​ File ​​​​​​​​ Input: def.txt ​​​​​​​​ Output: server.txt ​​​​​​​​""" ​​​​​​​​fin = open("def.txt", "r") ​​​​​​​​fout = open("server.txt", "w") ​​​​​​​​""" ​​​​​​​​ Server Information ​​​​​​​​ IP: 127.0.0.1 ​​​​​​​​ PORT: 1234 ​​​​​​​​""" ​​​​​​​​IP,PORT = "127.0.0.1", 1234 ​​​​​​​​# crete a server socket ​​​​​​​​serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ​​​​​​​​serverSocket.bind((IP,PORT)) ​​​​​​​​serverSocket.listen(5) ​​​​​​​​# Accept the client connection ​​​​​​​​clientSocket, address = serverSocket.accept() ​​​​​​​​# Set Non Blocking ​​​​​​​​clientSocket.setblocking(False) ​​​​​​​​serverSocket.setblocking(False) ​​​​​​​​EOF = False ​​​​​​​​while True: ​​​​​​​​ try: ​​​​​​​​ data = clientSocket.recv(1024).decode() ​​​​​​​​ print(f"Client: {data}") ​​​​​​​​ if EOF and data == "END": break ​​​​​​​​ elif EOF: continue ​​​​​​​​ fout.write(data) ​​​​​​​​ except : ​​​​​​​​ pass ​​​​​​​​ try: ​​​​​​​​ data = fin.readline() ​​​​​​​​ if not data: raise EOFError ​​​​​​​​ clientSocket.send(data.encode()) ​​​​​​​​ print(f"Server: {data}") ​​​​​​​​ except EOFError: ​​​​​​​​ clientSocket.send(b'END') ​​​​​​​​ print(f"Server: END") ​​​​​​​​ EOF = True ​​​​​​​​ time.sleep(1) ​​​​​​​​# Close the connection ​​​​​​​​clientSocket.close() ​​​​​​​​serverSocket.close()
    • Client
      C
      ​​​​​​​​#include <stdio.h> ​​​​​​​​#include <winsock.h> ​​​​​​​​int main(){ ​​​​​​​​ FILE *fin, *fout; ​​​​​​​​ fin = fopen("abc.txt", "r"); ​​​​​​​​ fout = fopen("client.txt","w"); ​​​​​​​​ SOCKET sd; ​​​​​​​​ WSADATA wsadata; ​​​​​​​​ struct sockaddr_in serv; ​​​​​​​​ int i,n; ​​​​​​​​ char str[2048]=""; ​​​​​​​​ 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 mode = 1; ​​​​​​​​ ioctlsocket(sd,FIONBIO,&mode); ​​​​​​​​ while(1){ ​​​​​​​​ char* c_line = NULL; ​​​​​​​​ size_t len = 0; ​​​​​​​​ int status = getline(&c_line,&len,fin); ​​​​​​​​ if (status != EOF) { ​​​​​​​​ send(sd,c_line, strlen(c_line)+1,0); ​​​​​​​​ printf("Send: %s\n",c_line); ​​​​​​​​ } ​​​​​​​​ else{ ​​​​​​​​ send(sd,"END", 4,0); ​​​​​​​​ printf("Send: END\n"); ​​​​​​​​ } ​​​​​​​​ memset(str,0,sizeof(str)); ​​​​​​​​ n = recv(sd,str, sizeof(str), 0); ​​​​​​​​ if (n > 0) { ​​​​​​​​ str[n] = '\0'; ​​​​​​​​ printf("Receive: %s\n",str); ​​​​​​​​ if (strcmp(str, "END\0") == 0 && status == EOF) { ​​​​​​​​ break; ​​​​​​​​ } ​​​​​​​​ else if (strcmp(str, "END\0") == 0) { ​​​​​​​​ continue; ​​​​​​​​ } ​​​​​​​​ fprintf(fout,"%s",str); ​​​​​​​​ } ​​​​​​​​ else if (n == 0){ ​​​​​​​​ break; ​​​​​​​​ } ​​​​​​​​ Sleep(100); ​​​​​​​​ } ​​​​​​​​ closesocket(sd); ​​​​​​​​ fclose(fin); ​​​​​​​​ fclose(fout); ​​​​​​​​ WSACleanup(); ​​​​​​​​}
      Python
      ​​​​​​​​import socket ​​​​​​​​import time ​​​​​​​​""" ​​​​​​​​ File ​​​​​​​​ Input: abc.txt ​​​​​​​​ Output: client.txt ​​​​​​​​""" ​​​​​​​​fin = open("abc.txt", "r") ​​​​​​​​fout = open("client.txt", "w") ​​​​​​​​""" ​​​​​​​​ Client Information ​​​​​​​​ IP: 127.0.0.1 ​​​​​​​​ PORT: 1234 ​​​​​​​​""" ​​​​​​​​IP,PORT = "127.0.0.1", 1234 ​​​​​​​​# Create a client socket ​​​​​​​​clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ​​​​​​​​clientSocket.connect((IP,PORT)) ​​​​​​​​# Set Non Blocking ​​​​​​​​clientSocket.setblocking(False) ​​​​​​​​EOF = False ​​​​​​​​while True: ​​​​​​​​ try: ​​​​​​​​ data = clientSocket.recv(1024).decode() ​​​​​​​​ print(f"Server: {data}") ​​​​​​​​ if EOF and data == "END": break ​​​​​​​​ elif EOF: continue ​​​​​​​​ fout.write(data) ​​​​​​​​ except: ​​​​​​​​ pass ​​​​​​​​ try: ​​​​​​​​ data = fin.readline() ​​​​​​​​ if not data: raise EOFError ​​​​​​​​ clientSocket.send(data.encode()) ​​​​​​​​ print(f"Client: {data}") ​​​​​​​​ except EOFError: ​​​​​​​​ EOF = True ​​​​​​​​ print(f"Client: END") ​​​​​​​​ clientSocket.send(b'END') ​​​​​​​​ time.sleep(1) ​​​​​​​​fin.close() ​​​​​​​​fout.close() ​​​​​​​​# Close the connection ​​​​​​​​clientSocket.close() ​​​​​​​​fout.close() ​​​​​​​​fin.close()
  • 執行結果
    image
  • 備註
    • 為了知道雙方都已經傳送完畢,因此作了以下動作
      • 自己輸入完成,EOF的指標會傳出True,並傳END給Server
      • 當收到END時要判斷自己是否也EOF

第四題

  • 程式碼
    • Sever
      C++
      ​​​​​​​​#include <iostream> ​​​​​​​​#include <string> ​​​​​​​​#include <winsock.h> ​​​​​​​​#include <vector> ​​​​​​​​#include <time.h> ​​​​​​​​using namespace std; ​​​​​​​​int main(){ ​​​​​​​​ SOCKET sd; ​​​​​​​​ vector<SOCKET> clnt_sd; ​​​​​​​​ u_long mode = 1; ​​​​​​​​ WSADATA wsadata; ​​​​​​​​ struct sockaddr_in serv,clnt1,clnt2; ​​​​​​​​ int i,n; ​​​​​​​​ char str[2048]; ​​​​​​​​ 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"); ​​​​​​​​ time_t start, end; ​​​​​​​​ end = time(NULL); ​​​​​​​​ start = time(NULL); ​​​​​​​​ SOCKET clnt = accept(sd, (struct sockaddr *) &clnt1,&clnt_len1 ); ​​​​​​​​ printf("Client connected.\n"); ​​​​​​​​ ioctlsocket(clnt,FIONBIO,&mode); ​​​​​​​​ clnt_sd.push_back(clnt); ​​​​​​​​ clnt = accept(sd, (struct sockaddr *) &clnt1,&clnt_len1 ); ​​​​​​​​ printf("Client connected.\n"); ​​​​​​​​ ioctlsocket(clnt,FIONBIO,&mode); ​​​​​​​​ clnt_sd.push_back(clnt); ​​​​​​​​ while(1){ ​​​​​​​​ for (int i = 0; i<clnt_sd.size(); i++){ ​​​​​​​​ // Receive from client ​​​​​​​​ n = recv(clnt_sd[i],str, 2048, 0); ​​​​​​​​ if (n>0){ ​​​​​​​​ printf("(%i) %s\n",i+1,str); ​​​​​​​​ for (int j=0; j<clnt_sd.size(); j++){ ​​​​​​​​ if (i==j) continue; ​​​​​​​​ // Send to other clients ​​​​​​​​ send(clnt_sd[j],str, strlen(str)+1,0); ​​​​​​​​ } ​​​​​​​​ } ​​​​​​​​ else if (n == 0){ ​​​​​​​​ // Client disconnected ​​​​​​​​ goto end; ​​​​​​​​ } ​​​​​​​​ } ​​​​​​​​ } ​​​​​​​​ end: ​​​​​​​​ closesocket(sd); ​​​​​​​​ for (int i=0; i<clnt_sd.size(); i++) ​​​​​​​​ closesocket(clnt_sd[i]); ​​​​​​​​ WSACleanup(); ​​​​​​​​}
      Python
      ​​​​​​​​import socket ​​​​​​​​import time ​​​​​​​​""" ​​​​​​​​ Server Information ​​​​​​​​ IP: 127.0.0.1 ​​​​​​​​ PORT: 1234 ​​​​​​​​""" ​​​​​​​​IP,PORT = "127.0.0.1", 1234 ​​​​​​​​# crete a server socket ​​​​​​​​serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ​​​​​​​​serverSocket.bind((IP,PORT)) ​​​​​​​​serverSocket.listen(5) ​​​​​​​​serverSocket.setblocking(False) ​​​​​​​​# crete client socket ​​​​​​​​clientSocket = [] ​​​​​​​​# Waiting for connteing (5 seconds) ​​​​​​​​start,end = time.time(),time.time() ​​​​​​​​while end-start < 5: ​​​​​​​​ try: ​​​​​​​​ conn, addr = serverSocket.accept() ​​​​​​​​ print(f"Connect to {addr}") ​​​​​​​​ conn.setblocking(False) ​​​​​​​​ clientSocket.append(conn) ​​​​​​​​ except: ​​​​​​​​ pass ​​​​​​​​ end = time.time() ​​​​​​​​time.sleep(5) ​​​​​​​​breaked = False ​​​​​​​​while True: ​​​​​​​​ for i, client in enumerate(clientSocket): ​​​​​​​​ try: ​​​​​​​​ data = client.recv(1024).decode() ​​​​​​​​ print(f"({i}) {data}") ​​​​​​​​ for j,sock in enumerate(clientSocket): ​​​​​​​​ if j == i: continue ​​​​​​​​ n = sock.send(data.encode()) ​​​​​​​​ if n == 0: ​​​​​​​​ breaked = True ​​​​​​​​ break ​​​​​​​​ if breaked: break ​​​​​​​​ except: ​​​​​​​​ pass ​​​​​​​​ if breaked: break ​​​​​​​​for i in clientSocket: ​​​​​​​​ i.close()
    • Client
      C
      ​​​​​​​​#include <stdio.h> ​​​​​​​​#include <winsock.h> ​​​​​​​​#include <time.h> ​​​​​​​​int main(){ ​​​​​​​​ FILE *fin, *fout; ​​​​​​​​ SOCKET sd; ​​​​​​​​ WSADATA wsadata; ​​​​​​​​ struct sockaddr_in serv; ​​​​​​​​ int i,n; ​​​​​​​​ 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"); ​​​​​​​​ char fileName[1024]; ​​​​​​​​ printf("Enter file name: "); ​​​​​​​​ scanf("%s", fileName, sizeof(fileName)); ​​​​​​​​ fin = fopen(fileName, "r"); ​​​​​​​​ if (fin == NULL){ ​​​​​​​​ printf("File not found\n"); ​​​​​​​​ return 1; ​​​​​​​​ } ​​​​​​​​ memset(fileName,0,sizeof(fileName)); ​​​​​​​​ printf("Enter exports file name: "); ​​​​​​​​ scanf("%s", fileName, sizeof(fileName)); ​​​​​​​​ fout = fopen(fileName, "w"); ​​​​​​​​ if (fin == NULL){ ​​​​​​​​ printf("File not found\n"); ​​​​​​​​ return 1; ​​​​​​​​ } ​​​​​​​​ u_long mode = 1; ​​​​​​​​ ioctlsocket(sd,FIONBIO,&mode); ​​​​​​​​ Sleep(5000); ​​​​​​​​ while(1){ ​​​​​​​​ char* c_line = NULL; ​​​​​​​​ size_t len = 0; ​​​​​​​​ int status = getline(&c_line,&len,fin); // Read line from file ​​​​​​​​ char buffer[2048] = ""; ​​​​​​​​ if (status == EOF){ ​​​​​​​​ // Send END to server ​​​​​​​​ int n = send(sd,"END", 3+1,0); ​​​​​​​​ if (n == SOCKET_ERROR){ ​​​​​​​​ break; ​​​​​​​​ } ​​​​​​​​ printf("Send: %s\n","END"); ​​​​​​​​ } ​​​​​​​​ else{ ​​​​​​​​ // Send line to server ​​​​​​​​ send(sd,c_line, strlen(c_line)+1,0); ​​​​​​​​ printf("Send: %s\n",c_line); ​​​​​​​​ } ​​​​​​​​ free(c_line); ​​​​​​​​ n = recv(sd,buffer, 2048, 0); ​​​​​​​​ if (n>0){ ​​​​​​​​ // Receive line from server ​​​​​​​​ buffer[n] = '\0'; ​​​​​​​​ if (strcmp(buffer,"END") == 0 && status == EOF){ ​​​​​​​​ printf("Received: %s\n",buffer); ​​​​​​​​ break; ​​​​​​​​ } ​​​​​​​​ else if (strcmp(buffer,"END") == 0){ ​​​​​​​​ printf("Received: %s\n",buffer); ​​​​​​​​ continue; ​​​​​​​​ } ​​​​​​​​ else{ ​​​​​​​​ printf("Received: %s\n",buffer); ​​​​​​​​ fprintf(fout,"%s",buffer); ​​​​​​​​ } ​​​​​​​​ } ​​​​​​​​ else if (n == 0){ ​​​​​​​​ break; ​​​​​​​​ } ​​​​​​​​ Sleep(1000); ​​​​​​​​ } ​​​​​​​​ closesocket(sd); ​​​​​​​​ fclose(fin); ​​​​​​​​ fclose(fout); ​​​​​​​​ WSACleanup(); ​​​​​​​​}
      Python
      ​​​​​​​​import socket ​​​​​​​​import time ​​​​​​​​""" ​​​​​​​​ Server Information ​​​​​​​​ IP: 127.0.0.1 ​​​​​​​​ PORT: 1234 ​​​​​​​​""" ​​​​​​​​IP,PORT = "127.0.0.1", 1234 ​​​​​​​​# crete a server socket ​​​​​​​​serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ​​​​​​​​serverSocket.bind((IP,PORT)) ​​​​​​​​serverSocket.listen(5) ​​​​​​​​serverSocket.setblocking(False) ​​​​​​​​# crete client socket ​​​​​​​​clientSocket = [] ​​​​​​​​# Waiting for connteing (5 seconds) ​​​​​​​​start,end = time.time(),time.time() ​​​​​​​​while end-start < 5: ​​​​​​​​ try: ​​​​​​​​ conn, addr = serverSocket.accept() ​​​​​​​​ print(f"Connect to {addr}") ​​​​​​​​ conn.setblocking(False) ​​​​​​​​ clientSocket.append(conn) ​​​​​​​​ except: ​​​​​​​​ pass ​​​​​​​​ end = time.time() ​​​​​​​​time.sleep(5) ​​​​​​​​breaked = False ​​​​​​​​while True: ​​​​​​​​ for i, client in enumerate(clientSocket): ​​​​​​​​ try: ​​​​​​​​ data = client.recv(1024).decode() ​​​​​​​​ print(f"({i}) {data}") ​​​​​​​​ for j,sock in enumerate(clientSocket): ​​​​​​​​ if j == i: continue ​​​​​​​​ n = sock.send(data.encode()) ​​​​​​​​ if n == 0: ​​​​​​​​ breaked = True ​​​​​​​​ break ​​​​​​​​ if breaked: break ​​​​​​​​ except: ​​​​​​​​ pass ​​​​​​​​ if breaked: break ​​​​​​​​for i in clientSocket: ​​​​​​​​ i.close()
  • 執行結果
    image

第五題

  • 程式碼
    • Sever
      C++
      ​​​​​​​​#include <stdio.h> ​​​​​​​​#include <winsock.h> ​​​​​​​​#include <vector> ​​​​​​​​using namespace std; ​​​​​​​​int main(){ ​​​​​​​​ SOCKET sd; ​​​​​​​​ vector<SOCKET> clientsd; ​​​​​​​​ 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); ​​​​​​​​ int clnt_len=sizeof(clnt); ​​​​​​​​ printf("Server waits.\n"); ​​​​​​​​ SOCKET clnt_sd = accept(sd, (struct sockaddr *) &clnt,&clnt_len ); ​​​​​​​​ printf("Client is connected.\n"); ​​​​​​​​ clientsd.push_back(clnt_sd); ​​​​​​​​ u_long mode = 1; ​​​​​​​​ ioctlsocket(sd,FIONBIO,&mode); ​​​​​​​​ while(1){ ​​​​​​​​ clnt_sd = accept(sd, (struct sockaddr *) &clnt,&clnt_len ); ​​​​​​​​ if (clnt_sd != INVALID_SOCKET){ ​​​​​​​​ clientsd.push_back(clnt_sd); ​​​​​​​​ } ​​​​​​​​ vector<int> disconnect; ​​​​​​​​ for (int i = 0; i<clientsd.size();i++){ ​​​​​​​​ int n = send(clientsd[i],str, strlen(str)+1,0); ​​​​​​​​ if (n <= 0){ ​​​​​​​​ disconnect.push_back(i); ​​​​​​​​ printf("Client %d is disconnected.\n",i); ​​​​​​​​ } ​​​​​​​​ } ​​​​​​​​ for (auto i:disconnect){ ​​​​​​​​ closesocket(clientsd[i]); ​​​​​​​​ clientsd.erase(clientsd.begin()+i); ​​​​​​​​ } ​​​​​​​​ printf("(server send): %s\n",str); ​​​​​​​​ Sleep(1000); ​​​​​​​​ } ​​​​​​​​ closesocket(sd); ​​​​​​​​ for (int i = 0; i<clientsd.size();i++){ ​​​​​​​​ closesocket(clientsd[i]); ​​​​​​​​ } ​​​​​​​​ WSACleanup(); ​​​​​​​​ system("pause"); ​​​​​​​​}
      Python
      ​​​​​​​​import socket ​​​​​​​​import time ​​​​​​​​""" ​​​​​​​​ The Data I want to send to the clinet ​​​​​​​​""" ​​​​​​​​DATA = "Something Smell" ​​​​​​​​FREQ = 1 ​​​​​​​​""" ​​​​​​​​ Server Information ​​​​​​​​ IP: 127.0.0.1 ​​​​​​​​ PORT: 1234 ​​​​​​​​""" ​​​​​​​​IP,PORT = "127.0.0.1", 1234 ​​​​​​​​# crete server socket ​​​​​​​​serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ​​​​​​​​serverSocket.bind((IP,PORT)) ​​​​​​​​serverSocket.listen(5) ​​​​​​​​# A list for client socket ​​​​​​​​clientSocket = [] ​​​​​​​​sd,addr = serverSocket.accept() ​​​​​​​​clientSocket.append(sd) ​​​​​​​​print(f"Client {addr} connected") ​​​​​​​​serverSocket.setblocking(False) ​​​​​​​​while True: ​​​​​​​​ try: ​​​​​​​​ sd, addr = serverSocket.accept() ​​​​​​​​ clientSocket.append(sd) ​​​​​​​​ print(f"Client {addr} connected") ​​​​​​​​ except: ​​​​​​​​ pass ​​​​​​​​ disconnect = [] ​​​​​​​​ for i,conn in enumerate(clientSocket): ​​​​​​​​ try: ​​​​​​​​ conn.send(DATA.encode()) ​​​​​​​​ except ConnectionResetError: ​​​​​​​​ disconnect.append(i) ​​​​​​​​ for i in disconnect: ​​​​​​​​ clientSocket[i].close() ​​​​​​​​ clientSocket.pop(i) ​​​​​​​​ print(f"Client {i} disconnected") ​​​​​​​​ time.sleep(FREQ) ​​​​​​​​for i in clientSocket: ​​​​​​​​ i.close()
    • Client
      C++
      ​​​​​​​​#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("(from server): %s\n",str); ​​​​​​​​ } ​​​​​​​​ closesocket(sd); ​​​​​​​​ WSACleanup(); ​​​​​​​​}
      Python
      ​​​​​​​​import socket ​​​​​​​​""" ​​​​​​​​ Server Information ​​​​​​​​ IP: 127.0.0.1 ​​​​​​​​ PORT: 1234 ​​​​​​​​""" ​​​​​​​​IP,PORT = "127.0.0.1", 1234 ​​​​​​​​# crete a socket connet to server ​​​​​​​​sd = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ​​​​​​​​sd.connect((IP,PORT)) ​​​​​​​​print(f"Connect to server {IP}:{PORT}") ​​​​​​​​while True: ​​​​​​​​ data = sd.recv(1024).decode() ​​​​​​​​ print(f"Server: {data}") ​​​​​​​​sd.close()
  • 執行結果
    image
  • 備註
    • 當Server因為對方關閉連線,並將該連線踢出list中

心得

這周作業交了non blocking mode,感覺他像是一個有不耐煩的人,沒收到就直接回傳-1,雖然更有彈性了,但是要找霸哥 aka bug,就很困難。

這周作業感覺變難做了,感覺要考慮很多情況,而且加上非阻攔模式下有夠難debug,我發現錯誤時一直拿wireshark,發明這個的人真電。

在寫作業其實有遇到一個小問題,我以為Python也要像C那樣去看recv回傳的結果,結果會報錯,原來要改成try/except,雖然小麻煩,但我覺得比C易讀很多。

附錄

檔案的連結