# 網路程式設計 UDP作業 學生: 1084837廖經翰 ## 練習1. 以UDP來一送一收 這次的作業練習1是利用socket的UDP來讓一個client端傳送資訊給一個server端接收,來達到一送一收的動作 執行畫面: <center>server</center> <center><img style="margin-top:auto;border:1px #eee;width:70%;" src="https://i.imgur.com/oEqTmWD.png" /></center> <br> <center>client</center> <center><img style="margin-top:auto;border:1px #eee;width:70%;" src="https://i.imgur.com/Bj0Xfl2.png" /></center> <br> server程式碼: ```C= #include<stdio.h> #include<winsock.h> int main() { //set WSA and initial WSAStartup SOCKET sd; WSADATA wsadata; struct sockaddr_in serv,clnt; //設定Server的結構 serv.sin_addr.s_addr = inet_addr( "127.0.0.1" ); serv.sin_family = AF_INET; serv.sin_port = htons( 12345 ); char str[100]; int n,i; //呼叫WSAStartup()註冊WinSock DLL的使用 n = WSAStartup( 0x101 , (WSADATA*) &wsadata ); //使用UDP協定 sd = socket( AF_INET , SOCK_DGRAM , 0 ); int len_serv = sizeof( serv ); int len_clnt = sizeof( clnt ); //綁定serv結構裡設定的資訊 n = bind( sd , (struct sockaddr*) &serv , len_serv ); printf("Ready to recv on 12345...\n"); //接收到訊息之後才知道是誰傳過來 n = recvfrom ( sd , str , 100 , 0 , (struct sockaddr*) &clnt , &len_clnt ); printf( "recv:%s (%d)\n" , str , n ); //關閉TCP socket closesocket(sd); //結束WinSock DLL的使用 WSACleanup(); system("pause"); } ``` client程式碼: ```C= #include<stdio.h> #include<winsock.h> int main() { //set WSA and initial WSAStartup SOCKET sd; WSADATA wsadata; struct sockaddr_in serv,clnt; //設定Server的結構 serv.sin_addr.s_addr = inet_addr( "127.0.0.1" ); serv.sin_family = AF_INET; serv.sin_port = htons( 12345 ); char str[100]; int n,i; //呼叫WSAStartup()註冊WinSock DLL的使用 n = WSAStartup( 0x101 , (WSADATA*) &wsadata ); //使用UDP協定 sd = socket( AF_INET , SOCK_DGRAM , 0 ); int len_serv = sizeof( serv ); int len_clnt = sizeof( clnt ); //綁定serv結構裡設定的資訊 n = bind( sd , (struct sockaddr*) &serv , len_serv ); printf("Ready to recv on 12345...\n"); //接收到訊息之後才知道是誰傳過來 n = recvfrom ( sd , str , 100 , 0 , (struct sockaddr*) &clnt , &len_clnt ); printf( "recv:%s (%d)\n" , str , n ); //關閉TCP socket closesocket(sd); //結束WinSock DLL的使用 WSACleanup(); system("pause"); } ``` ## 練習2. 以UDP來一送二收 作業練習2是利用socket的UDP來讓一個client傳送兩個不同的資訊給server1與server2接收,來達到一送二收的動作 執行畫面: <center>server1</center> <center><img style="margin-top:auto;border:1px #eee;width:70%;" src="https://i.imgur.com/DAvE5kP.png" /></center> <br> <center>server2</center> <center><img style="margin-top:auto;border:1px #eee;width:70%;" src="https://i.imgur.com/riTU6x0.png" /></center> <br> <center>client</center> <center><img style="margin-top:auto;border:1px #eee;width:70%;" src="https://i.imgur.com/okK1IcT.png" /></center> <br> server1程式碼: ```C= #include<stdio.h> #include<winsock.h> int main() { //set WSA and initial WSAStartup SOCKET sd; WSADATA wsadata; struct sockaddr_in serv , clnt; //設定Server的結構 serv.sin_addr.s_addr = inet_addr( "127.0.0.1" ); serv.sin_family = AF_INET; serv.sin_port = htons( 12345 ); char str[100]; char *ip; int port; int n , i; //呼叫WSAStartup()註冊WinSock DLL的使用 n = WSAStartup( 0x101 , (WSADATA *) &wsadata ); //使用UDP協定 sd = socket( AF_INET , SOCK_DGRAM , 0 ); int len_serv = sizeof( serv ); int len_clnt = sizeof( clnt ); //綁定serv結構裡設定的資訊 n = bind( sd , (struct sockaddr*) &serv , len_serv ); printf("Ready to recv on 12345...\n"); while(1) { //接收傳送過來的訊息 n = recvfrom( sd , str , 100 , 0 , (struct sockaddr*) &clnt , &len_clnt ); printf( "recv:%s (%d)\n" , str , n ); } //關閉TCP socket closesocket(sd); //結束WinSock DLL的使用 WSACleanup(); system("pause"); } ``` server2程式碼: ```C= #include<stdio.h> #include<winsock.h> int main() { //set WSA and initial WSAStartup SOCKET sd; WSADATA wsadata; struct sockaddr_in serv,clnt; //設定Server的結構 serv.sin_addr.s_addr = inet_addr( "127.0.0.1" ); serv.sin_family = AF_INET; serv.sin_port = htons( 12346 ); char str[100]; char *ip; int port; int n , i; //呼叫WSAStartup()註冊WinSock DLL的使用 n = WSAStartup( 0x101 , (WSADATA *) &wsadata ); //使用UDP協定 sd = socket( AF_INET , SOCK_DGRAM , 0 ); int len_serv = sizeof( serv ); int len_clnt = sizeof( clnt ); //綁定serv結構裡設定的資訊 n = bind( sd , (struct sockaddr*) &serv , len_serv ); printf("Ready to recv on 12346...\n"); while(1) { //接收傳送過來的訊息 n = recvfrom( sd , str , 100 , 0 , (struct sockaddr*) &clnt , &len_clnt ); printf( "recv:%s (%d)\n" , str , n ); } //關閉TCP socket closesocket(sd); //結束WinSock DLL的使用 WSACleanup(); system("pause"); } ``` client程式碼: ```C= #include<stdio.h> #include<winsock.h> int main() { //set WSA and initial WSAStartup SOCKET sd; WSADATA wsadata; struct sockaddr_in serv , serv1; char str[100]="I love NP!"; char str1[100]="I love Algorithm!"; int n , i; //呼叫WSAStartup()註冊WinSock DLL的使用 n = WSAStartup( 0x101 , (WSADATA *) &wsadata ); //使用UDP協定 sd = socket( AF_INET , SOCK_DGRAM , 0 ); //設定Server的結構 serv.sin_addr.s_addr = inet_addr( "127.0.0.1") ; serv.sin_family = AF_INET; serv.sin_port = htons( 12345 ); //設定Server1的結構 serv1.sin_addr.s_addr = inet_addr( "127.0.0.1" ); serv1.sin_family = AF_INET; serv1.sin_port = htons( 12346 ); int len_serv = sizeof( serv ); int len_serv1 = sizeof( serv1 ); //傳送10次 for( i = 0 ; i < 10 ; i++ ) { //傳送給server資訊 n = sendto( sd , str , strlen(str)+1 , 0 , (struct sockaddr*) &serv , len_serv ); printf( "Send to 12345:%s (%d)\n", str , n+1 ); Sleep(1000); //傳送給server1資訊 n = sendto( sd , str1 , strlen(str1)+1 , 0 , (struct sockaddr*) &serv1 , len_serv1 ); printf( "Send to 12346:%s (%d)\n" , str1 , n+1 ); Sleep(1000); } //關閉TCP socket closesocket(sd); //結束WinSock DLL的使用 WSACleanup(); system("pause"); } ``` ## 練習3. 以UDP來二送一收,並顯示來源端資訊 作業練習3是利用socket的UDP來讓client1和client2去傳送各別的資訊給server接收,來達到二送一收的動作,並顯示傳送過來的ip與port number 執行畫面: <center>server</center> <center><img style="margin-top:auto;border:1px #eee;width:70%;" src="https://i.imgur.com/GdOZZBC.png" /></center> <br> <center>client1</center> <center><img style="margin-top:auto;border:1px #eee;width:70%;" src="https://i.imgur.com/GW06NPD.png" /></center> <br> <center>client2</center> <center><img style="margin-top:auto;border:1px #eee;width:70%;" src="https://i.imgur.com/ok6ARuR.png" /></center> <br> server程式碼: ```C= #include<stdio.h> #include<winsock.h> int main() { //set WSA and initial WSAStartup SOCKET sd; WSADATA wsadata; struct sockaddr_in serv , clnt; //設定Server的結構 serv.sin_addr.s_addr = inet_addr( "127.0.0.1" ); serv.sin_family = AF_INET; serv.sin_port = htons( 12345 ); char str[100]; char *ip; int port; int n , i; //呼叫WSAStartup()註冊WinSock DLL的使用 n = WSAStartup( 0x101 , (WSADATA*) &wsadata ); //使用UDP協定 sd = socket( AF_INET , SOCK_DGRAM , 0 ); int len_serv = sizeof( serv ); int len_clnt = sizeof( clnt ); //綁定serv結構裡設定的資訊 n = bind( sd , (struct sockaddr*) &serv , len_serv ); printf("Ready to recv on 12345...\n"); while(1) { //接收傳送過來的訊息 n = recvfrom( sd , str , 100 , 0 , (struct sockaddr*) &clnt , &len_clnt ); //將32位元的IPv4地址轉換為十進制字串,並且知道是從哪一個ip傳送過來 ip = inet_ntoa( clnt.sin_addr ); //將一個16位元的整數轉換為host位元組順序,並且知道是從哪一個port傳送過來 port = ntohs( clnt.sin_port ); printf( "recv:%s (%d) from:%s(%d)\n" , str , n , ip , port ); } //關閉TCP socket closesocket(sd); //結束WinSock DLL的使用 WSACleanup(); system("pause"); } ``` client1程式碼: ```C= #include<stdio.h> #include<winsock.h> int main() { //set WSA and initial WSAStartup SOCKET sd; WSADATA wsadata; struct sockaddr_in serv; char str[100]="I love NP!"; int n , i; //呼叫WSAStartup()註冊WinSock DLL的使用 n = WSAStartup( 0x101 , (WSADATA*) &wsadata ); //使用UDP協定 sd = socket( AF_INET , SOCK_DGRAM , 0 ); //設定Server的結構 serv.sin_addr.s_addr = inet_addr( "127.0.0.1" ); serv.sin_family = AF_INET; serv.sin_port = htons( 12345 ); int len_serv = sizeof( serv ); //傳送10次給Server for( i = 0 ; i < 10 ; i++ ) { //傳送給server資訊 n = sendto( sd , str , strlen(str)+1 , 0 , (struct sockaddr*) &serv , len_serv ); printf( "Client 1 sends to 12345:%s (%d)\n" , str , n+1 ); Sleep(1000); } //關閉TCP socket closesocket(sd); //結束WinSock DLL的使用 WSACleanup(); system("pause"); } ``` client2程式碼: ```C= #include<stdio.h> #include<winsock.h> int main() { //set WSA and initial WSAStartup SOCKET sd; WSADATA wsadata; struct sockaddr_in serv; char str[100]="I love Algorithm!"; int n , i; //呼叫WSAStartup()註冊WinSock DLL的使用 n = WSAStartup( 0x101 , (WSADATA *) &wsadata ); //使用UDP協定 sd = socket( AF_INET , SOCK_DGRAM , 0 ); //設定Server的結構 serv.sin_addr.s_addr = inet_addr( "127.0.0.1" ); serv.sin_family = AF_INET; serv.sin_port = htons( 12345 ); int len_serv = sizeof( serv ); //傳送10次給Server for( i = 0 ; i < 10 ; i++ ) { //傳送給server資訊 n = sendto( sd , str , strlen(str)+1 , 0 , (struct sockaddr*) &serv , len_serv ); printf( "Client 2 sends to 12345:%s (%d)\n" , str , n+1 ); Sleep(1000); } //關閉TCP socket closesocket(sd); //結束WinSock DLL的使用 WSACleanup(); system("pause"); } ``` ## 練習4. UDP實作變化: 當傳送對象是固定對象 作業練習4是當傳送對象是固定對象的時候,利用socket的UDP來讓client再傳送之前先連接至固定的server,連接之後再把資訊傳送給server,這樣就可以傳送給固定的對象 執行畫面: <center>server</center> <center><img style="margin-top:auto;border:1px #eee;width:70%;" src="https://i.imgur.com/6BvTpIJ.png" /></center> <br> <center>client</center> <center><img style="margin-top:auto;border:1px #eee;width:70%;" src="https://i.imgur.com/IX7r9VH.png" /></center> <br> server程式碼: ```C= #include<stdio.h> #include<winsock.h> int main() { //set WSA and initial WSAStartup SOCKET sd; WSADATA wsadata; struct sockaddr_in serv , clnt; //設定Server的結構 serv.sin_addr.s_addr = inet_addr( "127.0.0.1" ); serv.sin_family = AF_INET; serv.sin_port = htons( 12345 ); char str[100]; char *ip; int port; int n , i; //呼叫WSAStartup()註冊WinSock DLL的使用 n = WSAStartup( 0x101 , (WSADATA*) &wsadata ); //使用UDP協定 sd = socket( AF_INET , SOCK_DGRAM , 0 ); int len_serv = sizeof( serv ); int len_clnt = sizeof( clnt ); //綁定serv結構裡設定的資訊 n = bind( sd , (struct sockaddr*) &serv , len_serv ); printf("Ready to recv on 12345...\n"); while(1) { //接收傳送過來的訊息 n = recvfrom( sd , str , 100 , 0 , (struct sockaddr*) &clnt , &len_clnt ); //將32位元的IPv4地址轉換為十進制字串,並且知道是從哪一個ip傳送過來 ip = inet_ntoa( clnt.sin_addr ); //將一個16位元的整數轉換為host位元組順序,並且知道是從哪一個port傳送過來 port = ntohs( clnt.sin_port ); printf( "recv:%s (%d) from:%s(%d)\n" , str , n , ip , port ); } //關閉TCP socket closesocket(sd); //結束WinSock DLL的使用 WSACleanup(); system("pause"); } ``` client程式碼: ```C= #include<stdio.h> #include<winsock.h> int main() { //set WSA and initial WSAStartup SOCKET sd; WSADATA wsadata; struct sockaddr_in serv; char str[100]="I love NP!"; int n , i; //呼叫WSAStartup()註冊WinSock DLL的使用 n = WSAStartup( 0x101 , (WSADATA *) &wsadata ); //使用UDP協定 sd = socket( AF_INET , SOCK_DGRAM , 0 ); //設定Server的結構 serv.sin_addr.s_addr = inet_addr( "127.0.0.1" ); serv.sin_family = AF_INET; serv.sin_port = htons( 12345 ); int len_serv = sizeof( serv ); //因使用send(),所以在傳送之前要先連接至server,連接之後才能傳送資訊 connect( sd , (struct sockaddr*) &serv , len_serv ); //傳送10次給Server for( i = 0 ; i < 10 ; i++ ) { //傳送給server資訊 n = send( sd , str , strlen(str)+1 , 0 ); printf( "Client 1 sends to 12345:%s (%d)\n" , str , n+1 ); Sleep(1000); } //關閉TCP socket closesocket(sd); //結束WinSock DLL的使用 WSACleanup(); system("pause"); } ``` ## 練習5. UDP實作變化: 當傳送端想用固定port 作業練習5是當傳送端想用固定port的時候,利用socket的UDP來讓client再傳送之前先綁定自己設定的ip與port number,綁定完成之後再連接至server,連接完之後再把資訊傳送給server,這樣server接收到訊息後就知道是從哪一個固定的port number傳送過來的 執行畫面: <center>server</center> <center><img style="margin-top:auto;border:1px #eee;width:70%;" src="https://i.imgur.com/M6sQpd6.png" /></center> <br> <center>client</center> <center><img style="margin-top:auto;border:1px #eee;width:70%;" src="https://i.imgur.com/a8QlJWZ.png" /></center> <br> server程式碼: ```C= #include<stdio.h> #include<winsock.h> int main() { //set WSA and initial WSAStartup SOCKET sd; WSADATA wsadata; struct sockaddr_in serv , clnt; //設定Server的結構 serv.sin_addr.s_addr = inet_addr( "127.0.0.1" ); serv.sin_family = AF_INET; serv.sin_port = htons( 12345 ); char str[100]; char *ip; int port; int n , i; //呼叫WSAStartup()註冊WinSock DLL的使用 n = WSAStartup( 0x101 , (WSADATA*) &wsadata ); //使用UDP協定 sd = socket( AF_INET , SOCK_DGRAM , 0 ); int len_serv = sizeof( serv ); int len_clnt = sizeof( clnt ); //綁定serv結構裡設定的資訊 n = bind( sd , (struct sockaddr*) &serv , len_serv ); printf("Ready to recv on 12345...\n"); while(1) { //接收傳送過來的訊息 n = recvfrom( sd , str , 100 , 0 , (struct sockaddr*) &clnt , &len_clnt ); //將32位元的IPv4地址轉換為十進制字串,並且知道是從哪一個ip傳送過來 ip = inet_ntoa( clnt.sin_addr ); //將一個16位元的整數轉換為host位元組順序,並且知道是從哪一個port傳送過來 port = ntohs( clnt.sin_port ); printf( "recv:%s (%d) from:%s(%d)\n" , str , n , ip , port ); } //關閉TCP socket closesocket(sd); //結束WinSock DLL的使用 WSACleanup(); system("pause"); } ``` client程式碼: ```C= #include<stdio.h> #include<winsock.h> int main() { //set WSA and initial WSAStartup SOCKET sd; WSADATA wsadata; struct sockaddr_in serv , clnt; char str[100]="I love NP!"; int n , i; //呼叫WSAStartup()註冊WinSock DLL的使用 n = WSAStartup( 0x101 , (WSADATA *) &wsadata ); //使用UDP協定 sd = socket( AF_INET , SOCK_DGRAM , 0 ); int len_clnt = sizeof( clnt ); //設定client的結構 clnt.sin_addr.s_addr = inet_addr( "127.0.0.1" ); clnt.sin_family = AF_INET; clnt.sin_port = htons( 22222 ); //set 0 is random port //綁定client結構裡設定的資訊 bind( sd , (struct sockaddr*) &clnt , len_clnt ); //設定server的結構 serv.sin_addr.s_addr = inet_addr( "127.0.0.1" ); serv.sin_family = AF_INET; serv.sin_port = htons( 12345 ); int len_serv = sizeof( serv ); //因使用send(),所以在傳送之前要先連接至server,連接之後才能傳送資訊 connect( sd , (struct sockaddr*) &serv , len_serv ); //傳送10次給server for( i = 0 ; i < 10 ; i++ ) { //傳送給server資訊 n = send( sd , str , strlen(str)+1 , 0 ); printf( "Client 1 sends to 12345:%s (%d)\n" , str , n+1 ); Sleep(1000); } //關閉TCP socket closesocket(sd); //結束WinSock DLL的使用 WSACleanup(); system("pause"); } ``` ## 練習6. UDP實作變化: 當傳接送端不關心傳送來源 作業練習6是利用socket的UDP來讓client傳送資訊給server接收,server是使用recv()來接收資訊,所以資訊的來源雖然不知道是從哪裡來的,但是也可以正常的接收資訊 執行畫面: <center>server</center> <center><img style="margin-top:auto;border:1px #eee;width:70%;" src="https://i.imgur.com/1SzEgBA.png" /></center> <br> <center>client</center> <center><img style="margin-top:auto;border:1px #eee;width:70%;" src="https://i.imgur.com/FILJiQt.png" /></center> <br> server程式碼: ```C= #include<stdio.h> #include<winsock.h> int main() { //set WSA and initial WSAStartup SOCKET sd; WSADATA wsadata; struct sockaddr_in serv , clnt; //設定Server的結構 serv.sin_addr.s_addr = inet_addr( "127.0.0.1" ); serv.sin_family = AF_INET; serv.sin_port = htons( 12345 ); char str[100]; char *ip; int port; int n , i; //呼叫WSAStartup()註冊WinSock DLL的使用 n = WSAStartup( 0x101 , (WSADATA *) &wsadata ); //使用UDP協定 sd = socket( AF_INET , SOCK_DGRAM , 0 ); int len_serv = sizeof( serv ); int len_clnt = sizeof( clnt ); //綁定serv結構裡設定的資訊 n = bind( sd , (struct sockaddr*) &serv , len_serv ); printf("Ready to recv on 12345...\n"); while(1) { //使用recv()的時候,就不用管傳送的來源 n = recv( sd , str , 100 , 0 ); printf( "recv:%s (%d) \n" , str , n , ip , port ); } //關閉TCP socket closesocket(sd); //結束WinSock DLL的使用 WSACleanup(); system("pause"); } ``` client程式碼: ```C= #include<stdio.h> #include<winsock.h> int main() { //set WSA and initial WSAStartup SOCKET sd; WSADATA wsadata; struct sockaddr_in serv , clnt; char str[100]="I love NP!"; int n , i; //呼叫WSAStartup()註冊WinSock DLL的使用 n = WSAStartup( 0x101 , (WSADATA *) &wsadata ); //使用UDP協定 sd = socket( AF_INET , SOCK_DGRAM , 0 ); int len_clnt = sizeof( clnt ); //設定client的結構 clnt.sin_addr.s_addr = inet_addr( "127.0.0.1" ); clnt.sin_family = AF_INET; clnt.sin_port = htons( 22222 ); //set 0 is random port //綁定client結構裡設定的資訊 bind( sd , (struct sockaddr*) &clnt , len_clnt ); //設定server的結構 serv.sin_addr.s_addr = inet_addr( "127.0.0.1" ); serv.sin_family = AF_INET; serv.sin_port = htons( 12345 ); int len_serv = sizeof( serv ); //因使用send(),所以在傳送之前要先連接至server,連接之後才能傳送資訊 connect( sd , (struct sockaddr*) &serv , len_serv ); //傳送10次給server for( i = 0 ; i < 10 ; i++ ) { //傳送給server資訊 n = send( sd , str , strlen(str)+1 , 0 ); printf( "Client 1 sends to 12345:%s (%d)\n" , str , n+1 ); Sleep(1000); } //關閉TCP socket closesocket(sd); //結束WinSock DLL的使用 WSACleanup(); system("pause"); } ``` ## 本週心得 這次老師教的課程為UDP的應用,因為之前老師教的TCP傳輸都是必較嚴謹的,client端與server端都必須要設定好資訊才能順利傳輸,這樣程式上也比較難去寫,但是這次教的UDP傳送我覺得自己寫起來比TCP還要來的簡單與容易,而且UDP的傳輸就是有傳出去就好不用管有沒有順利的傳送過去,我也很喜歡做這種不負責任的事情,所以我非常喜歡UDP的方式傳輸,希望之後老師可以再教多一點有關於UDP的各種應用或是把TCP與UDP整合在一起應用,這樣可能會碰出更有趣的火花,老師上傳的教學影片也非常的淺顯易懂,完全不會很複雜但也可以學到很多東西,程式碼的部分老師也講解得非常詳細,如果有不懂的地方還可以回去在聽一次複習,所以我非常喜歡上老師的課程,很期待老師下一周的上課內容與新的應用,謝謝老師,謝謝助教大哥批改作業! <center><img style="margin-top:auto;border:1px #eee;width:70%;" src="https://i.imgur.com/6KcTU9p.png" /></center> <br> <br> <center><img style="margin-top:auto;border:1px #eee;width:70%;" src="https://i.imgur.com/LfWfwOt.png" /></center> <br> ### 作者: 廖經翰