Linux下 面向連線的 UDP通訊

2021-05-27 06:55:39 字數 3845 閱讀 6782

1、編寫udp server程式的步驟

(1)使用socket()來建立乙個udp socket,第二個引數為sock_dgram。  

(2)初始化sockaddr_in結構的變數,並賦值

這裡使用「2030」作為服務程式的埠,使用「inaddr_any」作為繫結的ip位址即任何主機上的位址。  

(3)使用bind()把上面的socket和定義的ip位址和埠繫結。這裡檢查bind()是否執行成功,如果有錯誤就退出。這樣可以防止服務程式重複執行的問題。  

(4)進入無限迴圈程式,使用recvfrom()進入等待狀態,直到接收到客戶程式傳送的資料,就處理收到的資料,並向客戶程式傳送反饋。這裡是直接把收到的資料發回給客戶程式。

2、srv.cpp程式內容

#include #include #include #include int main()

struct sockaddr_in srvaddr, clientaddr;

srvaddr.sin_family=af_inet;

srvaddr.sin_addr.s_addr=htonl(inaddr_any);

srvaddr.sin_port=htons(2030);

if(bind(srvsock, (struct sockaddr *)&srvaddr, sizeof(srvaddr))==-1)

socklen_t len=sizeof(srvaddr);

while(1)

;char sendmsg[128]=;

memcpy(sendmsg, "hello, client", 128);

recvfrom(srvsock, recvmsg, 128, 0, (struct sockaddr *)&clientaddr, &len);

printf("接收到資料%s\n", recvmsg);

sendto(srvsock, sendmsg, 128, 0, (struct sockaddr *)&clientaddr, len);

printf("傳送資料%s\n", sendmsg);

}return 0;

}

1、編寫udp client程式的步驟   

(1)初始化sockaddr_in結構的變數,並賦值。

這裡使用「2030」作為連線的服務程式的埠,從命令列引數讀取ip位址,並且判斷ip位址是否符合要求。   

(2)使用socket()來建立乙個udp socket,第二個引數為sock_dgram。  

(3)使用connect()來建立與服務程式的連線。

與tcp協議不同,udp的connect()並沒有與服務程式三次握手。上面說了udp是非連線的,實際上也可以是連線的。使用連線的udp,kernel可以直接返回錯誤資訊給使用者程式,從而避免由於沒有接收到資料而導致呼叫recvfrom()一直等待下去,看上去好像客戶程式沒有反應一樣。

(4)向服務程式傳送資料,因為使用連線的udp,所以使用write()來替代sendto()。這裡的資料直接從標準輸入讀取使用者輸入。

(5)接收服務程式發回的資料,同樣使用read()來替代recvfrom()。  

(6)處理接收到的資料,這裡是直接輸出到標準輸出上。  

注意:

1. 在linux作業系統中,套接字可視為檔案,在呼叫connect()函式之後就可以呼叫read()和write()直接在其上進行接收和傳送。

2. 當用recvfrom()函式接收的時候並沒有錯誤提示,而當用read()函式讀取的時候有錯誤提示。原因尚未知。

client.cpp程式內容:  

#include #include #include #include #include #include int main()

struct sockaddr_in destaddr;

destaddr.sin_family=af_inet;

destaddr.sin_addr.s_addr=inet_addr("127.0.0.1");

destaddr.sin_port=htons(2030);

socklen_t len=sizeof(destaddr);

connect(clientsock, (struct sockaddr *)&destaddr, len);

/*即便鏈結出錯,也不會返回任何資訊

if(connect(clientsock,(struct sockaddr *)&destaddr, len)==-1)

*/char sendmsg[128]=;

memcpy(sendmsg, "hello, server", 128);

char recvmsg[128]=;

/* 用sendto()和recvfrom()沒有鏈結錯誤提示

sendto(clientsock, sendmsg, 128, 0, (struct sockaddr *)&destaddr, len);

while(1)

;recvfrom(clientsock, recvmsg, 128, 0, (struct sockaddr *)&destaddr, &len);

printf("接收到資料%s\n", recvmsg);

break;}*/

write(clientsock, sendmsg, 128);

while(1)

recvmsg[n]=0;

printf("接收到資料%s\n", recvmsg);

break;

} }

執行例子程式

1、編譯例子程式   

使用如下命令來編譯例子程式:   

gcc -wall -o srv srv.cpp   

gcc -wall -o client client.cpp   

編譯完成生成了udpserv和udpclient兩個可執行程式。   

2、執行udp server程式

執行./srv &命令來啟動服務程式。我們可以使用netstat -ln命令來觀察服務程式繫結的ip位址和埠,部分輸出資訊如下:  

active internet connections (only servers)  

proto recv-q send-q local address foreign address state  

udp        0      0 0.0.0.0:2030            0.0.0.0:*

可以看到udp處有「0.0.0.0:2030」的內容,說明服務程式已經正常執行,可以接收主機上任何ip位址且埠為2030的資料。  

如果這時再執行./srv &命令,就會看到如下資訊:   

繫結失敗:

address already in use  

說明已經有乙個服務程式在執行了。

出現這種情況可以用命令kill結束正在執行的程式,並重新開啟。

3、執行udp client程式

執行./client 命令來啟動客戶程式,使用127.0.0.1來連線服務程式,執行效果如下:

接收到資料hello, client 

輸入的資料都正確從服務程式返回了,按ctrl+c可以退出程式。  

如果服務程式沒有啟動,而執行客戶程式,就會看到如下資訊:

read error: connection refused  

說明指定的ip位址和埠沒有服務程式繫結,客戶程式就退出了。

這就是使用connect()的好處,注意,這裡錯誤資訊是在向服務程式傳送資料後收到的,而不是在呼叫connect()時。

如果使用tcpdump程式來抓包,會發現收到的是icmp的錯誤資訊。

Linux實現UDP連線

udp是無連線不可靠的ip協議,和tcp有所不同。udp伺服器呼叫socket bind listen 完成套接字初始化後,呼叫accept 阻塞等待處於監聽埠的狀態。udp客戶端呼叫socket 初始化後,呼叫connect 傳送syn欄位並阻塞等待應答。客戶端如果一直與服務端連線,服務端退出後重...

Linux下面的編譯和連線

編譯和連線 編譯通常是對單個原始檔進行編譯成.o檔案 要加上 c選項,比如 gcc o aa.o c aa.cpp 否則會提示找不到main函式 因為有些模組只是提供單元函式 並沒有main函式 編譯只檢查基本語法,對於引用的外部函式,只用能找到其宣告就可以正確編譯通過,比如在cpp檔案中包含了引用...

Linux下的UDP連線程式設計

udp是無連線不可靠的ip協議,和tcp有所不同。udp伺服器呼叫socket bind listen 完成套接字初始化後,呼叫accept 阻塞等待處於監聽埠的狀態。udp客戶端呼叫socket 初始化後,呼叫connect 傳送syn欄位並阻塞等待應答。客戶端如果一直與服務端連線,服務端退出後重...