Socket编程(C语言实现)——UDP协议(进程间通信AF_UNIX)的流式(SOCK_STREAM)+报式(SOCK_DGRAM)传输【循环监听】
Socket編程
目前較為流行的網絡編程模型是客戶機/服務器通信模式
客戶進程向服務器進程發出要求某種服務的請求,服務器進程響應該請求。如圖所示,通常,一個服務器進程會同時為多個客戶端進程服務,圖中服務器進程B1同時為客戶進程A1、A2和B2提供服務。
Socket概述
①?? 所謂Socket通常也稱作“套接字”,用于描述IP地址和端口,是一個通信鏈的句柄。應用程序通常通過“套接字”向網絡發出請求或者應答網絡請求。
②?? Socket是連接運行在網絡上的兩個程序間的雙向通信的端點。
③?? 網絡通訊其實指的就是Socket間的通訊。
④?? 通訊的兩端都有Socket,數據在兩個Socket之間通過IO來進行傳輸。
套接字socket的類型
(1)流式套接字(SOCK_STREAM)
提供面向連接、可靠的數據傳輸服務,數據無差錯、無重復的發送,且按發送順序接收(TCP協議)
(2)數據報式套接字(SOCK_DGRAM)
提供無連接服務,數據包以獨立包形式發送,不提供無措保證,數據可能丟失,并且接收順序混亂(UDP協議)
(3)原始套接字(SOCK_RAM)
套接字(socket)
socket起源于Unix,而Unix/Linux基本哲學之一就是“一切皆文件”,都可以用“打開open –> 讀寫write/read –> 關閉close”模式來操作。Socket就是該模式的一個實現,socket即是一種特殊的文件,一些socket函數就是對其進行的操作(讀/寫IO、打開、關閉).說白了Socket是應用層與TCP/IP協議族通信的中間軟件抽象層,它是一組接口。在設計模中,Socket其實就是一個門面模式,它把復雜的TCP/IP協議族隱藏在Socket接口后面,對用戶來說,一組簡單的接口就是全部,讓Socket去組織數據,以符合指定的協議。
隨著Unix的應用推廣,套接字有被引進了windows等操作系統。套接字通常只與同一區域的套接字交換數據,windows socket只支持一個通信區域:網際域(AF_INET),這個域被使用忘記協議簇的通信進程使用。
基于UDP(面向無連接)的socket編程
報式傳輸:“客戶端”,1.socket()函數;2.bind()函數,綁定客戶端的地址與端口【網絡間通信AF_STREAM】或者路徑【進程間通信AF_DGRAM】,以便于后續服務端sendto()函數參數的填寫。若服務器端只是收不發數據,即,服務端有recvfrom()函數無sendto()函數,則客戶端不需要bind()函數;若服務端要發送數據,即,有sendto()函數,則客戶端需要bind()函數;?3.客戶端sendto()函數參數,填寫服務端的地址與端口【網絡間通信AF_STREAM】或者服務端路徑【進程間通信AF_DGRAM】的結構體地址與結構體長度,服務端必須有bind()函數;4.客戶端recvfrom()函數參數,NULL,會自動識別。
報式傳輸:“服務端”,1.socket()函數;2.bind()函數,綁定客戶端的地址與端口【網絡間通信AF_STREAM】或者路徑【進程間通信AF_DGRAM】,以便于后續客戶端sendto()函數參數的填寫。若服務器端只是收不發數據,即,服務端有recvfrom()函數無sendto()函數,則客戶端不需要bind()函數;3.服務端sendto()函數參數,填寫客戶端的地址與端口【網絡間通信AF_STREAM】或者客戶端路徑【進程間通信AF_DGRAM】的結構體地址與結構體長度,服務端必須有bind()函數;4.recvfrom()函數參數,NULL,會自動識別。
基于UDP(面向無連接)的socket編程(循環監聽)——流式套接字(SOCK_STREAM)
進程間通信AF_UNIX,典型的本地進程間通信
服務器:
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h>int main() {int iSocketFD = 0;int iNewFD = 0;struct sockaddr_un stLocalAddr = {0};char acBuf[1024]= {0};iSocketFD = socket(AF_UNIX, SOCK_STREAM, 0);if(0 > iSocketFD) {printf("創建socket失敗!\n");return 0;}stLocalAddr.sun_family = AF_UNIX;sprintf(stLocalAddr.sun_path, "./xxx");remove("./xxx");if(0 > bind(iSocketFD, (void *)&stLocalAddr, sizeof(stLocalAddr))){close(iSocketFD);printf("綁定地址失敗!\n");return -1;}if(0 > listen(iSocketFD, 5)){close(iSocketFD);printf("監聽失敗!\n");return -1;}while(1){iNewFD = accept(iSocketFD, NULL, NULL);if(0 > iNewFD){close(iSocketFD);printf("接收數據失敗!\n");return -1;}if(0 > recv(iNewFD, acBuf, sizeof(acBuf), 0)){close(iSocketFD);close(iNewFD);printf("接收失敗!\n");return -1;}else{printf("接收到的客戶端發來的信息是:%s\n", acBuf);}if(0 > send(iNewFD, "服務器", sizeof("服務器"), 0)){close(iSocketFD);close(iNewFD);printf("發送失敗!\n");return -1;}}return 0; }客戶端:
#include <stdio.h> #include <sys/socket.h> #include <sys/un.h> #include <sys/types.h>int main() {int iSocketFD = 0;struct sockaddr_un stRemoteAddr = {0}; char acBuf[1024] = {0};iSocketFD = socket(AF_UNIX, SOCK_STREAM, 0);if(0 > iSocketFD){printf("創建socket失敗!\n");return -1;}//填充對端地址stRemoteAddr.sun_family = AF_UNIX;sprintf(stRemoteAddr.sun_path,"./xxx"); //注意用sprintf//注意connect的第二個參數if(0 > connect(iSocketFD, (void *)&stRemoteAddr, sizeof(stRemoteAddr))){close(iSocketFD);printf("連接服務器失敗!\n");return -1;} if(0 > send(iSocketFD, "客戶端", sizeof("客戶端"), 0)){close(iSocketFD);printf("發送數據失敗!\n");return -1;}if(0 > recv(iSocketFD, acBuf, sizeof(acBuf), 0)){close(iSocketFD);printf("接收數據失敗!\n");return -1;}printf("客戶端接收到服務器發來的消息是:%s\n", acBuf);return 0; }測試:
1、編譯服務器、客戶端代碼:
[root@localhost unix_stream]# make socket_client_stream cc socket_client_stream.c -o socket_client_stream [root@localhost unix_stream]# make socket_server_stream cc socket_server_stream.c -o socket_server_stream2、執行服務端代碼:
[root@localhost unix_stream]# ./socket_server_stream 接收到的客戶端發來的信息是:客戶端 接收到的客戶端發來的信息是:客戶端3、執行客戶端代碼:
[root@localhost unix_stream]# ./socket_client_stream 客戶端接收到服務器發來的消息是:服務器 [root@localhost unix_stream]# ./socket_client_stream 客戶端接收到服務器發來的消息是:服務器?
基于UDP(面向無連接)的socket編程——數據報式套接字(SOCK_DGRAM)
進程間通信AF_UNIX,典型的本地進程間通信
服務器:( ?循環監聽)
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h>int main() {int iSocketFD = 0;int iNewFD = 0;struct sockaddr_un stLocalAddr = {0};struct sockaddr_un stRemoteAddr = {0};char acBuf[1024]= {0};iSocketFD = socket(AF_UNIX, SOCK_DGRAM, 0);if(0 > iSocketFD) {printf("創建socket失敗!\n");return 0;}stLocalAddr.sun_family = AF_UNIX;sprintf(stLocalAddr.sun_path, "./server");remove("./server");//綁定之前要刪除原來的文件if(0 > bind(iSocketFD, (void *)&stLocalAddr, sizeof(stLocalAddr))){close(iSocketFD);printf("綁定地址失敗!\n");return -1;}stRemoteAddr.sun_family = AF_UNIX;sprintf(stRemoteAddr.sun_path, "./client");while(1){if(0 > recvfrom(iSocketFD, acBuf, sizeof(acBuf), 0, NULL, NULL)){close(iSocketFD);printf("接收失敗!\n");return -1;}else{printf("接收到的客戶端發來的信息是:%s\n", acBuf);}if(0 > sendto(iSocketFD, "服務器", sizeof("服務器"), 0, (void *)&stRemoteAddr, sizeof(stRemoteAddr))){close(iSocketFD);printf("發送失敗!\n");return -1;}}return 0; }客戶端:
#include <stdio.h> #include <sys/socket.h> #include <sys/un.h> #include <sys/types.h>int main() {int iSocketFD = 0;struct sockaddr_un stRemoteAddr = {0}; struct sockaddr_un stLocalAddr = {0}; char acBuf[1024] = {0};iSocketFD = socket(AF_UNIX, SOCK_DGRAM, 0);if(0 > iSocketFD){printf("創建socket失敗!\n");return -1;}stLocalAddr.sun_family = AF_UNIX;sprintf(stLocalAddr.sun_path, "./client"); //注意用sprintf remove("./client"); //綁定之前要刪除原來的if(0 > bind(iSocketFD, (void *)&stLocalAddr, sizeof(stLocalAddr))){printf("綁定地址失敗!\n");return -1;}//填充對端地址//報式傳輸,只發不收可以不bind,要發要收必須要bindstRemoteAddr.sun_family = AF_UNIX;sprintf(stRemoteAddr.sun_path, "./server"); //注意用sprintf if(0 > sendto(iSocketFD, "客戶端", sizeof("客戶端"), 0, (void *)&stRemoteAddr, sizeof(stRemoteAddr))){close(iSocketFD);printf("發送數據失敗!\n");return -1;}if(0 > recvfrom(iSocketFD, acBuf, sizeof(acBuf), 0, NULL, NULL)){close(iSocketFD);printf("接收數據失敗!\n");return -1;}printf("客戶端接收到服務器發來的消息是:%s\n", acBuf);return 0; }測試:
1、編譯服務器和客戶端:
[root@localhost unix_dgram]# make socket_client_dgram cc socket_client_dgram.c -o socket_client_dgram [root@localhost unix_dgram]# make socket_server_dgram cc socket_server_dgram.c -o socket_server_dgram2、服務器監聽:
[root@localhost unix_dgram]# ./socket_server_dgram 接收到的客戶端發來的信息是:客戶端 接收到的客戶端發來的信息是:客戶端3、客戶端連接服務器:
[root@localhost unix_dgram]# ./socket_client_dgram 客戶端接收到服務器發來的消息是:服務器 [root@localhost unix_dgram]# ./socket_client_dgram 客戶端接收到服務器發來的消息是:服務器參考鏈接:https://blog.csdn.net/zhang___yong/article/details/78702559
java:https://www.cnblogs.com/wzy330782/p/5479833.html
基于TCP/IP和UDP協議的socket編程結構解析:https://blog.csdn.net/zhengnice/article/details/51428080
總結
以上是生活随笔為你收集整理的Socket编程(C语言实现)——UDP协议(进程间通信AF_UNIX)的流式(SOCK_STREAM)+报式(SOCK_DGRAM)传输【循环监听】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C语言——把结构体数据封装成TLV格式的
- 下一篇: Socket编程(C语言实现)—— 为什