# 網路程式設計 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>
### 作者: 廖經翰