色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Socket編程的目的就是如何實現這兩端之間的通信

GReq_mcu168 ? 來源:玩轉單片機 ? 2020-06-28 17:15 ? 次閱讀

一、什么是socket?

Socket的英文原義是“孔”或“插座”。在編程中,Socket被稱做套接字,是網絡通信中的一種約定。Socket編程的應用無處不在,我們平時用的QQ、微信、瀏覽器等程序,都與Socket編程有關。我們平時使用瀏覽器查資料,這個過程的技術原理是怎樣的呢?

我們平時使用瀏覽器,大致就是這樣的一個過程。這里有兩個重要的名詞:服務端與客戶端。

Socket編程的目的就是如何實現這兩端之間的通信

1、Socket編程在嵌入式中也很重要

Socket編程不僅僅在互聯網方面很重要,在我們的嵌入式方面也是非常的重要,因為現在很多電子設備都趨向于聯網。比如很多嵌入式工作的招聘要求都會有這一條要求:

說一點題外話,還在學校的朋友,如果感覺到很迷茫,不知道學什么的時候,可以上招聘網站上看看自己未來工作相關的職位的任職要求,這樣就可以總結自己的一些不足、比較有針對性的去學習。

二、Socket編程中的幾個重要概念

Socket編程用于解決我們客戶端與服務端之間通信的問題。我們平時多多少少都有聽過IP地址、端口、TCP協議、UDP協議等概念,這些都與Socket編程中相關,想要知道怎么用起來,當然得先了解它們的一些介紹。下面看一下這些專業術語的一些要點介紹:

1、什么是IP地址?

IP地址(InternetProtocolAddress)是指互聯網協議地址,又譯為網際協議地址。IP地址被用來給Internet上的電腦一個編號。我們可以把“個人電腦”比作“一臺電話”,那么“IP地址”就相當于“電話號碼”。若計算機1知道計算機2的IP地址,則計算機1就能訪問計算機2。

IP地址是一個32位的二進制數,通常被分割為4個“8位二進制數”(也就是4個字節)。IP地址通常用點分十進制表示成(a.b.c.d)的形式,其中,a,b,c,d都是0~255之間的十進制整數。例:點分十進IP地址(100.4.5.6),實際上是32位二進制數(01100100.00000100.00000101.00000110)。

IP地址有IPv4與IPv6之分,現在用得較多的是IPv4。其中,有一個特殊的IP地址需要我們記住:127.0.0.1,這是回送地址,即本地機,一般用來測試使用。后邊我們的實例中會用到。

關于IP地址還有很多知識要點,但是對于在Socket編程中的應用,我們暫且知道這么多就可以。

2、什么是TCP/IP端口?

上一點中我們提到,若計算機1知道計算機2的IP地址,則計算機1就能訪問計算機2。但是,我們要訪問計算機2中的不同的應用軟件,則還得需要一個信息:端口。端口使用16bit進行編號,即其范圍為:0~65536。但0~1023的端口一般由系統分配給特定的服務程序,例如 Web 服務的端口號為 80,FTP 服務的端口號為 21等。

3、什么是協議?

協議(Protocol)是通信雙方進行數據交互的一種約定。如TCP、UDP協議:

(1)TCP協議

TCP(Transmission Control Protocol 傳輸控制協議)是一種面向連接的、可靠的、基于字節流的傳輸層通信協議,數據可以準確發送,數據丟失會重發。TCP協議常用于web應用中。

TCP連接(三次握手)

TCP傳輸起始時,客戶端、服務端要完成三次數據交互工作才能建立連接,常稱為三次握手。可形象比喻為如下對話:

客戶端:服務端您好,我有數據要發給你,請求您開通訪問權限。

服務端:客戶端您好,已給您開通權限,您可以發送數據了。

客戶端:收到,謝謝。

具體示意圖為:

這里的SYN和ACK是都是標志位,其中SYN代表新建一個連接,ACK代表確認。其中m、n都是隨機數。具體說明如:

第一次握手:SYN標志位被置位,客戶端向服務端發送一個隨機數m。

第二次握手:ACK、SYN標志位被置位。服務端向客戶端發送m+1表示確認剛才收到的數據,同時向客戶端發送一個隨機數n。

第三次握手:ACK標志被置位。客戶端向服務端發送n+1表示確認收到數據。

TCP斷開(四次揮手)

TCP斷開連接時,客戶端、服務端要完成四次數據交互工作才能建立連接,常稱為四次揮手。可形象比喻為如下對話:

客戶端:服務端您好,我發送數據完畢了,即將和您斷開連接。

服務端:客戶端您好,我稍稍準備一下,再給您斷開

服務端:客戶端您好,我準備好了,您可以斷開連接了。

客戶端:好的,合作愉快!

具體示意圖為:

這里的FIN也是一個標志位,代表斷開連接。具體說明類似三次握手。

為什么建立連接只需要三次數據交互,而斷開連接需要四次呢?

建立連接時,服務端在監聽狀態下,收到建立連接請求的SYN報文后,把ACK和SYN放在一個報文里發送給客戶端。

而關閉連接時,當收到對方的FIN報文時,僅僅表示對方不再發送數據了但是還能接收數據,己方也未必全部數據都發送給對方了,所以己方可以立即close,也可以發送一些數據給對方后,再發送FIN報文給對方來表示同意現在關閉連接,因此,己方ACK和FIN一般都會分開發送。

(2)UDP協議

UDP(User Datagram Protocol, 用戶數據報協議)是一種無連接的傳輸層協議,提供面向事務的簡單不可靠信息傳送服務,可以保證通訊效率,傳輸延時小。例如視頻聊天應用中用的就是UDP協議,這樣可以保證及時丟失少量數據,視頻的顯示也不受很大影響。

4、什么是協議族?

協議族是多個協議的統稱。比如我們的TCP/IP協議族,其不僅僅是TCP協議、IP協議,而是多個協議的集合,其包含IP、TCP、UDP、FTP、SMTP等協議。

三、socket編程的API接口

1、Linux下的socket API接口

(1)創建socket:socket()函數

函數原型:

int socket(int af, int type, int protocol);

af參數:af 為地址族(Address Family),也就是 IP 地址類型,常用的有 AFINET 和 AFINET6,其前綴也可以是PF(Protocol Family),即PFINET 和 PFINET6。

type參數:type 為數據傳輸方式,常用的有 面向連接(SOCK_STREAM)方式(即TCP) 和 無連接(SOCK_DGRAM)的方式(即UDP)。

protocol參數:protocol 表示傳輸協議,常用的有IPPROTO_TCP和IPPTOTO_UDP,分別表示 TCP 傳輸協議和 UDP 傳輸協議。

使用示例:

創建TCP套接字:

int tcp_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

創建UDP套接字:

int udp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

(2)綁定套接字:bind()函數

函數原型:

int bind(int sock, struct sockaddr *addr, socklen_t addrlen);

sock參數:sock 為 socket 文件描述符。

addr參數:addr 為 sockaddr 結構體變量的指針。

addrlen參數:addrlen 為 addr 變量的大小,可由 sizeof() 計算得出。

使用示例:

將創建的套接字ServerSock與本地IP127.0.0.1、端口1314進行綁定:

/* 創建服務端socket */

int ServerSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

/* 設置服務端信息 */

struct sockaddr_in ServerSockAddr;

memset(&ServerSockAddr, 0, sizeof(ServerSockAddr)); // 給結構體ServerSockAddr清零

ServerSockAddr.sin_family = PF_INET; // 使用IPv4地址

ServerSockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");// 本機IP地址

ServerSockAddr.sin_port = htons(1314); // 端口

/* 綁定套接字 */

bind(ServerSock, (SOCKADDR*)&ServerSockAddr, sizeof(SOCKADDR));

其中structsockaddr_in類型的結構體變量用于保存IPv4的IP信息。若是IPv6,則有對應的結構體:

struct sockaddr_in6

{

sa_family_t sin6_family; // 地址類型,取值為AF_INET6

in_port_t sin6_port; // 16位端口號

uint32_t sin6_flowinfo; // IPv6流信息

struct in6_addr sin6_addr; // 具體的IPv6地址

uint32_t sin6_scope_id; // 接口范圍ID

};

(3)建立連接:connect()函數

函數原型:

int connect(int sock, struct sockaddr *serv_addr, socklen_t addrlen);

參數與bind()的參數類似。

使用示例:

int ClientSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

connect(ClientSock, (SOCKADDR*)&ServerSockAddr, sizeof(SOCKADDR));

(4)監聽:listen()函數

函數原型:

int listen(int sock, int backlog);

sock參數:sock 為需要進入監聽狀態的套接字。

backlog參數:backlog 為請求隊列的最大長度。

使用示例:

/* 進入監聽狀態 */

listen(ServerSock, 10);

(5)接收請求:accept()函數

函數原型:

int accept(int sock, struct sockaddr *addr, socklen_t *addrlen);

sock參數:sock 為服務器端套接字。

addr參數:addr 為 sockaddr_in 結構體變量。

addrlen參數:addrlen 為參數 addr 的長度,可由 sizeof() 求得。

返回值:一個新的套接字,用于與客戶端通信。

使用示例:

/* 監聽客戶端請求,accept函數返回一個新的套接字,發送和接收都是用這個套接字 */

int ClientSock = accept(ServerSock, (SOCKADDR*)&ClientAddr, &len);

(6)關閉:close()函數

函數原型:

int close(int fd);

fd:要關閉的文件描述符。

使用示例:

close(ServerSock);

(7)數據的接收和發送

數據收發函數有幾組:

read()/write()

recv()/send()

readv()/writev()

recvmsg()/sendmsg()

recvfrom()/sendto()

函數原型:

ssize_t read(int fd, void *buf, size_t count);

ssize_t write(int fd, const void *buf, size_t count);

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,

const struct sockaddr *dest_addr, socklen_t addrlen);

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,

struct sockaddr *src_addr, socklen_t *addrlen);

ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);

ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

這里介紹一下recv()/send()、recvfrom()/sendto()。

recv()函數:

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

sockfd參數:sockfd為要接收數據的套接字。

buf參數:buf 為要接收的數據的緩沖區地址。

len參數:len 為要接收的數據的字節數。

flags參數:flags 為接收數據時的選項,常設為0。

send()函數:

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

sockfd參數:sockfd為要發送數據的套接字。

buf參數:buf 為要發送的數據的緩沖區地址。

len參數:len 為要發送的數據的字節數。

flags參數:flags 為發送數據時的選項,常設為0。

recvfrom()函數:

ssize_t recvfrom(int sock, void *buf, size_t nbytes, int flags, struct sockadr *from, socklen_t *addrlen);

sock:用于接收UDP數據的套接字;

buf:保存接收數據的緩沖區地址;

nbytes:可接收的最大字節數(不能超過buf緩沖區的大小);

flags:可選項參數,若沒有可傳遞0;

from:存有發送端地址信息的sockaddr結構體變量的地址;

addrlen:保存參數 from 的結構體變量長度的變量地址值。

sendto()函數:

ssize_t sendto(int sock, void *buf, size_t nbytes, int flags, struct sockaddr *to, socklen_t addrlen);

sock:用于傳輸UDP數據的套接字;

buf:保存待傳輸數據的緩沖區地址;

nbytes:帶傳輸數據的長度(以字節計);

flags:可選項參數,若沒有可傳遞0;

to:存有目標地址信息的 sockaddr 結構體變量的地址;

addrlen:傳遞給參數 to 的地址值結構體變量的長度。

2、windows下的socket API接口

跟Linux下的差不多:

SOCKET socket(int af, int type, int protocol);

int bind(SOCKET sock, const struct sockaddr *addr, int addrlen);

int connect(SOCKET sock, const struct sockaddr *serv_addr, int addrlen);

int listen(SOCKET sock, int backlog);

SOCKET accept(SOCKET sock, struct sockaddr *addr, int *addrlen);

int closesocket( SOCKET s);

int send(SOCKET sock, const char *buf, int len, int flags);

int recv(SOCKET sock, char *buf, int len, int flags);

int recvfrom(SOCKET sock, char *buf, int nbytes, int flags, const struct sockaddr *from, int *addrlen);

int sendto(SOCKET sock, const char *buf, int nbytes, int flags, const struct sockadr *to, int addrlen);

3、TCP、UDP通信的socket編程過程圖

(1)TCP通信socket編程過程

(2)UDP通信socket編程過程

四、socket的應用實例

1、基于TCP的本地客戶端、服務端信息交互實例

本例的例子實現的功能為:本地TCP客戶端往本地TCP服務端發送數據,TCP服務端收到數據則會打印輸出,同時把原數據返回給TCP客戶端。這個例子類似于我們在做單片機的串口實驗時,串口上位機往我們的單片機發送數據,單片機收到數據則把該數據原樣返回給上位機。

(1)windows的程序:

服務端程序tcp_server.c:

#include

#include

#define BUF_LEN 100

int main(void)

{

WSADATA wd;

SOCKET ServerSock, ClientSock;

char Buf[BUF_LEN] = {0};

SOCKADDR ClientAddr;

SOCKADDR_IN ServerSockAddr;

int addr_size = 0, recv_len = 0;

/* 初始化操作sock需要的DLL */

WSAStartup(MAKEWORD(2,2),&wd);

/* 創建服務端socket */

if (-1 == (ServerSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))

{

printf("socket error! ");

exit(1);

}

/* 設置服務端信息 */

memset(&ServerSockAddr, 0, sizeof(ServerSockAddr)); // 給結構體ServerSockAddr清零

ServerSockAddr.sin_family = AF_INET; // 使用IPv4地址

ServerSockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");// 本機IP地址

ServerSockAddr.sin_port = htons(1314); // 端口

/* 綁定套接字 */

if (-1 == bind(ServerSock, (SOCKADDR*)&ServerSockAddr, sizeof(SOCKADDR)))

{

printf("bind error! ");

exit(1);

}

/* 進入監聽狀態 */

if (-1 == listen(ServerSock, 10))

{

printf("listen error! ");

exit(1);

}

addr_size = sizeof(SOCKADDR);

while (1)

{

/* 監聽客戶端請求,accept函數返回一個新的套接字,發送和接收都是用這個套接字 */

if (-1 == (ClientSock = accept(ServerSock, (SOCKADDR*)&ClientAddr, &addr_size)))

{

printf("socket error! ");

exit(1);

}

/* 接受客戶端的返回數據 */

int recv_len = recv(ClientSock, Buf, BUF_LEN, 0);

printf("客戶端發送過來的數據為:%s ", Buf);

/* 發送數據到客戶端 */

send(ClientSock, Buf, recv_len, 0);

/* 關閉客戶端套接字 */

closesocket(ClientSock);

/* 清空緩沖區 */

memset(Buf, 0, BUF_LEN);

}

/*如果有退出循環的條件,這里還需要清除對socket庫的使用*/

/* 關閉服務端套接字 */

//closesocket(ServerSock);

/* WSACleanup();*/

return 0;

}

客戶端程序tcp_client.c:

#include

#include

#define BUF_LEN 100

int main(void)

{

WSADATA wd;

SOCKET ClientSock;

char Buf[BUF_LEN] = {0};

SOCKADDR_IN ServerSockAddr;

/* 初始化操作sock需要的DLL */

WSAStartup(MAKEWORD(2,2),&wd);

/* 向服務器發起請求 */

memset(&ServerSockAddr, 0, sizeof(ServerSockAddr));

ServerSockAddr.sin_family = AF_INET;

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

ServerSockAddr.sin_port = htons(1314);

while (1)

{

/* 創建客戶端socket */

if (-1 == (ClientSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))

{

printf("socket error! ");

exit(1);

}

if (-1 == connect(ClientSock, (SOCKADDR*)&ServerSockAddr, sizeof(SOCKADDR)))

{

printf("connect error! ");

exit(1);

}

printf("請輸入一個字符串,發送給服務端:");

gets(Buf);

/* 發送數據到服務端 */

send(ClientSock, Buf, strlen(Buf), 0);

/* 接受服務端的返回數據 */

recv(ClientSock, Buf, BUF_LEN, 0);

printf("服務端發送過來的數據為:%s ", Buf);

memset(Buf, 0, BUF_LEN); // 重置緩沖區

closesocket(ClientSock); // 關閉套接字

}

// WSACleanup(); /*如果有退出循環的條件,這里還需要清除對socket庫的使用*/

return 0;

}

我們上邊的IP地址概念那一部分中,有強調127.0.0.1這個IP是一個特殊的IP地址,這是回送地址,即本地機,一般用來測試使用。這個例子中我們就用到了。此外,端口我們設置為1314,這是隨意設置的,只要范圍在1024~65536之間就可以。

本文使用的是gcc編譯器編譯(關于gcc編譯器的相關介紹可查看往期筆記:【C語言筆記】使用notepad++、MinGW來開發C程序及【C語言筆記】windows命令行下編譯C程序),編譯命令如下:

gcc tcp_client.c -o tcp_client.exe -lwsock32

gcc tcp_server.c -o tcp_server.exe -lwsock32

這里必須要加-lwsock32這個參數用于鏈接windows下socket編程必須的winsock2這個庫。若是使用集成開發環境,則需要把wsock32.lib放在工程目錄下,并在我們代碼中#include下面加上一行#pragmacomment(lib,"ws2_32.lib")代碼(這種情況本人未驗證,有興趣的朋友可嘗試)。

實驗現象:

先啟動服務端程序tcp_server.exe,再啟動客戶端程序tcp_client.exe,并在客戶端中輸入字符串,則當服務端會接收到字符串時會打印輸出,與此同時也會往客戶端返回相同的數據:

動圖:

(2)Linux的程序:

在linux下,“一切都是文件”,所以這里我們的套接字也當做文件來看待。

服務端程序linux_tcp_server.c:

#include

#include

#include

#include

#include

#include

#include

#define BUF_LEN 100

int main(void)

{

int ServerFd, ClientFd;

char Buf[BUF_LEN] = {0};

struct sockaddr ClientAddr;

int addr_len = 0, recv_len = 0;

struct sockaddr_in ServerSockAddr;

int optval = 1;

/* 創建服務端文件描述符 */

if (-1 == (ServerFd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))

{

printf("socket error! ");

exit(1);

}

/* 設置服務端信息 */

memset(&ServerSockAddr, 0, sizeof(ServerSockAddr)); // 給結構體ServerSockAddr清零

ServerSockAddr.sin_family = AF_INET; // 使用IPv4地址

ServerSockAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 自動獲取IP地址

ServerSockAddr.sin_port = htons(6666); // 端口

// 設置地址和端口號可以重復使用

if (setsockopt(ServerFd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0)

{

printf("setsockopt error! ");

exit(1);

}

/* 綁定操作,綁定前加上上面的socket屬性可重復使用地址 */

if (-1 == bind(ServerFd, (struct sockaddr*)&ServerSockAddr, sizeof(struct sockaddr)))

{

printf("bind error! ");

exit(1);

}

/* 進入監聽狀態 */

if (-1 == (listen(ServerFd, 10)))

{

printf("listen error! ");

exit(1);

}

addr_len = sizeof(struct sockaddr);

while (1)

{

/* 監聽客戶端請求,accept函數返回一個新的套接字,發送和接收都是用這個套接字 */

if (-1 == (ClientFd = accept(ServerFd, (struct sockaddr*)&ClientAddr, &addr_len)))

{

printf("accept error! ");

exit(1);

}

/* 接受客戶端的返回數據 */

if ((recv_len = recv(ClientFd, Buf, BUF_LEN, 0)) < 0)

{

printf("recv error! ");

exit(1);

}

printf("客戶端發送過來的數據為:%s ", Buf);

/* 發送數據到客戶端 */

send(ClientFd, Buf, recv_len, 0);

/* 關閉客戶端套接字 */

close(ClientFd);

/* 清空緩沖區 */

memset(Buf, 0, BUF_LEN);

}

return 0;

}

客戶端程序linux_tcp_client.c:

#include

#include

#include

#include

#include

#include

#define BUF_LEN 100

int main(void)

{

int ClientFd;

char Buf[BUF_LEN] = {0};

struct sockaddr_in ServerSockAddr;

/* 向服務器發起請求 */

memset(&ServerSockAddr, 0, sizeof(ServerSockAddr));

ServerSockAddr.sin_family = AF_INET;

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

ServerSockAddr.sin_port = htons(6666);

while (1)

{

/* 創建客戶端socket */

if (-1 == (ClientFd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))

{

printf("socket error! ");

exit(1);

}

/* 連接 */

if (-1 == connect(ClientFd, (struct sockaddr*)&ServerSockAddr, sizeof(ServerSockAddr)))

{

printf("connect error! ");

exit(1);

}

printf("請輸入一個字符串,發送給服務端:");

gets(Buf);

/* 發送數據到服務端 */

send(ClientFd, Buf, strlen(Buf), 0);

memset(Buf, 0, BUF_LEN); // 重置緩沖區

/* 接受服務端的返回數據 */

recv(ClientFd, Buf, BUF_LEN, 0);

printf("服務端發送過來的數據為:%s ", Buf);

memset(Buf, 0, BUF_LEN); // 重置緩沖區

close(ClientFd); // 關閉套接字

}

return 0;

}

Linux下編譯就不需要添加-lwsock32參數:

gcc linux_tcp_server.c -o linux_tcp_server

gcc linux_tcp_client.c -o linux_tcp_client

實驗現象:

在調試這份程序時,出現了綁定錯誤:

經上網查詢發現是端口重復使用,可以在調用bind()函數之前調用setsockopt()函數以解決端口重復使用的問題:

2、基于UDP的本地客戶端、服務端信息交互實例

(1)windows的程序

服務端程序udp_server.c:

#include

#include

#define BUF_LEN 100

int main(void)

{

WSADATA wd;

SOCKET ServerSock;

char Buf[BUF_LEN] = {0};

SOCKADDR ClientAddr;

SOCKADDR_IN ServerSockAddr;

int addr_size = 0;

/* 初始化操作sock需要的DLL */

WSAStartup(MAKEWORD(2,2),&wd);

/* 創建服務端socket */

if(-1 == (ServerSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)))

{

printf("socket error! ");

exit(1);

}

/* 設置服務端信息 */

memset(&ServerSockAddr, 0, sizeof(ServerSockAddr)); // 給結構體ServerSockAddr清零

ServerSockAddr.sin_family = AF_INET; // 使用IPv4地址

ServerSockAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 自動獲取IP地址

ServerSockAddr.sin_port = htons(1314); // 端口

/* 綁定套接字 */

if (-1 == (bind(ServerSock, (SOCKADDR*)&ServerSockAddr, sizeof(SOCKADDR))))

{

printf("bind error! ");

exit(1);

}

addr_size = sizeof(SOCKADDR);

while (1)

{

/* 接受客戶端的返回數據 */

int str_len = recvfrom(ServerSock, Buf, BUF_LEN, 0, &ClientAddr, &addr_size);

printf("客戶端發送過來的數據為:%s ", Buf);

/* 發送數據到客戶端 */

sendto(ServerSock, Buf, str_len, 0, &ClientAddr, addr_size);

/* 清空緩沖區 */

memset(Buf, 0, BUF_LEN);

}

/*如果有退出循環的條件,這里還需要清除對socket庫的使用*/

/* 關閉服務端套接字 */

//closesocket(ServerSock);

/* WSACleanup();*/

return 0;

}

客戶端程序udp_client.c:

#include

#include

#define BUF_LEN 100

int main(void)

{

WSADATA wd;

SOCKET ClientSock;

char Buf[BUF_LEN] = {0};

SOCKADDR ServerAddr;

SOCKADDR_IN ServerSockAddr;

int ServerAddrLen = 0;

/* 初始化操作sock需要的DLL */

WSAStartup(MAKEWORD(2,2),&wd);

/* 創建客戶端socket */

if (-1 == (ClientSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)))

{

printf("socket error! ");

exit(1);

}

/* 向服務器發起請求 */

memset(&ServerSockAddr, 0, sizeof(ServerSockAddr));

ServerSockAddr.sin_family = PF_INET;

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

ServerSockAddr.sin_port = htons(1314);

ServerAddrLen = sizeof(ServerAddr);

while (1)

{

printf("請輸入一個字符串,發送給服務端:");

gets(Buf);

/* 發送數據到服務端 */

sendto(ClientSock, Buf, strlen(Buf), 0, (struct sockaddr*)&ServerSockAddr, sizeof(ServerSockAddr));

/* 接受服務端的返回數據 */

recvfrom(ClientSock, Buf, BUF_LEN, 0, &ServerAddr, &ServerAddrLen);

printf("服務端發送過來的數據為:%s ", Buf);

memset(Buf, 0, BUF_LEN); // 重置緩沖區

}

closesocket(ClientSock); // 關閉套接字

// WSACleanup(); /*如果有退出循環的條件,這里還需要清除對socket庫的使用*/

return 0;

}

(2)Linux下的程序

服務端程序linux_udp_server.c:

#include

#include

#include

#include

#include

#include

#include

#define BUF_LEN 100

int main(void)

{

int ServerFd;

char Buf[BUF_LEN] = {0};

struct sockaddr ClientAddr;

struct sockaddr_in ServerSockAddr;

int addr_size = 0;

int optval = 1;

/* 創建服務端socket */

if ( -1 == (ServerFd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)))

{

printf("socket error! ");

exit(1);

}

/* 設置服務端信息 */

memset(&ServerSockAddr, 0, sizeof(ServerSockAddr)); // 給結構體ServerSockAddr清零

ServerSockAddr.sin_family = AF_INET; // 使用IPv4地址

ServerSockAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 自動獲取IP地址

ServerSockAddr.sin_port = htons(1314); // 端口

// 設置地址和端口號可以重復使用

if (setsockopt(ServerFd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0)

{

printf("setsockopt error! ");

exit(1);

}

/* 綁定操作,綁定前加上上面的socket屬性可重復使用地址 */

if (-1 == bind(ServerFd, (struct sockaddr*)&ServerSockAddr, sizeof(ServerSockAddr)))

{

printf("bind error! ");

exit(1);

}

addr_size = sizeof(ClientAddr);

while (1)

{

/* 接受客戶端的返回數據 */

int str_len = recvfrom(ServerFd, Buf, BUF_LEN, 0, &ClientAddr, &addr_size);

printf("客戶端發送過來的數據為:%s ", Buf);

/* 發送數據到客戶端 */

sendto(ServerFd, Buf, str_len, 0, &ClientAddr, addr_size);

/* 清空緩沖區 */

memset(Buf, 0, BUF_LEN);

}

close(ServerFd);

return 0;

}

客戶端程序linux_udp_client.c:

#include

#include

#include

#include

#include

#include

#define BUF_LEN 100

int main(void)

{

int ClientFd;

char Buf[BUF_LEN] = {0};

struct sockaddr ServerAddr;

int addr_size = 0;

struct sockaddr_in ServerSockAddr;

/* 創建客戶端socket */

if (-1 == (ClientFd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)))

{

printf("socket error! ");

exit(1);

}

/* 向服務器發起請求 */

memset(&ServerSockAddr, 0, sizeof(ServerSockAddr));

ServerSockAddr.sin_family = PF_INET;

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

ServerSockAddr.sin_port = htons(1314);

addr_size = sizeof(ServerAddr);

while (1)

{

printf("請輸入一個字符串,發送給服務端:");

gets(Buf);

/* 發送數據到服務端 */

sendto(ClientFd, Buf, strlen(Buf), 0, (struct sockaddr*)&ServerSockAddr, sizeof(ServerSockAddr));

/* 接受服務端的返回數據 */

recvfrom(ClientFd, Buf, BUF_LEN, 0, &ServerAddr, &addr_size);

printf("服務端發送過來的數據為:%s ", Buf);

memset(Buf, 0, BUF_LEN); // 重置緩沖區

}

close(ClientFd); // 關閉套接字

return 0;

}

實驗現象:

實驗現象如實例1。

五、總結

本筆記簡單介紹了一些與socket編程相關的一些知識點:IP地址,什么是端口,協議等。重點介紹了TCP、UDP通信的一些原理及其API接口的用法,并給出了windows和linux下的TCP、UDP通信實例。以上就是關于socket編程的一些總結,如有錯誤,歡迎指出!

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 嵌入式
    +關注

    關注

    5085

    文章

    19138

    瀏覽量

    305677
  • 通信
    +關注

    關注

    18

    文章

    6036

    瀏覽量

    136060
  • Socket
    +關注

    關注

    0

    文章

    212

    瀏覽量

    34722

原文標題:【socket筆記】TCP、UDP通信總結

文章出處:【微信號:mcu168,微信公眾號:硬件攻城獅】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    socket 和 WebSocket 的區別

    在現代網絡通信中,Socket和WebSocket是種常見的通信協議。它們在實現網絡通信、數據
    的頭像 發表于 11-12 14:33 ?468次閱讀

    socket 客戶與服務器的實現

    1. 理解Socket 在計算機網絡中,socket是一種通信機制,允許個程序(一個客戶和一個服務器)通過網絡進行
    的頭像 發表于 11-12 14:30 ?327次閱讀

    socket 與 RESTful API 的使用

    。 1.2 Socket的特點 雙向通信Socket支持客戶和服務器之間的雙向通信,可以
    的頭像 發表于 11-12 14:22 ?301次閱讀

    socket 加密通信實現方式

    在網絡通信中,數據的安全性至關重要。Socket 編程作為網絡通信的基礎,實現加密通信是保護數據
    的頭像 發表于 11-12 14:18 ?428次閱讀

    socket 網絡通信協議解析

    通信機制,它允許個程序(通常位于不同的計算機上)進行雙向通信。在網絡編程中,Socket被用來實現
    的頭像 發表于 11-12 14:04 ?686次閱讀

    socket 編程基礎入門

    Socket 編程基礎入門 在計算機網絡中,Socket 是一個抽象層,它將網絡通信的細節隱藏起來,為開發者提供了一個簡單的接口來發送和接收數據。S
    的頭像 發表于 11-12 14:03 ?332次閱讀

    C語言中的socket編程基礎

    Socket編程簡介 Socket是一種通信機制,允許程序之間進行通信。在C語言中,
    的頭像 發表于 11-01 16:51 ?344次閱讀

    socket編程中的阻塞與非阻塞

    在網絡編程中, socket 是一個非常重要的概念,它提供了一個抽象層,使得開發者可以不必關心底層的網絡通信細節。 socket 編程中的阻
    的頭像 發表于 11-01 16:13 ?217次閱讀

    什么是socket編程 socket與tcp/ip協議的關系

    什么是Socket編程 Socket編程是一種網絡編程技術,它允許程序之間進行
    的頭像 發表于 11-01 16:01 ?362次閱讀

    瞬時極性法電容兩端極性判斷

    瞬時極性法電容兩端極性判斷是電子電路中的一個重要問題,涉及到電容的工作原理、特性以及在電路中的應用。 一、電容的基本概念 電容的定義 電容是一種電子元件,能夠存儲電荷。它的單位是法拉(F),通常用微
    的頭像 發表于 08-21 16:01 ?1309次閱讀

    簡述socket編程中的常用函數

    Socket編程是一種基于TCP/IP協議的網絡編程技術,它允許應用程序通過網絡進行通信。在Socket
    的頭像 發表于 08-16 10:49 ?402次閱讀

    如何理解socket編程接口

    不同計算機之間進行通信的方法。在網絡編程中,Socket被廣泛用于實現客戶和服務器
    的頭像 發表于 08-16 10:48 ?444次閱讀

    電容兩端的電壓會發生驟然的變化

    電容兩端的電壓會發生驟然的變化是一個非常重要的電子學現象,它在許多電子設備和系統中都有著廣泛的應用。 電容的基本特性 電容是一種電子元件,它能夠存儲電荷。電容的基本特性是它的電荷和電壓之間的關系,即
    的頭像 發表于 07-11 09:47 ?1511次閱讀

    鴻蒙開發實戰:【網絡管理-Socket連接】

    Socket在網絡通信方面的應用,展示了Socket兩端設備的連接驗證、聊天通信方面的應用。
    的頭像 發表于 03-19 22:04 ?900次閱讀
    鴻蒙開發實戰:【網絡管理-<b class='flag-5'>Socket</b>連接】

    物聯網LWIP之socket編程

    Socket的位置,作為用戶層與其他層的交互媒介。LWIP實現Socket需要操作系統的幫助,如下圖所示。二,Socket編程的基礎知識1.
    的頭像 發表于 01-18 08:00 ?1272次閱讀
    物聯網LWIP之<b class='flag-5'>socket</b><b class='flag-5'>編程</b>
    主站蜘蛛池模板: 最近中文字幕在线中文视频| 白人大战34厘米黑人BD| 国产精品 日韩精品 欧美| 午夜影院c绿象| 国产自产视频在线观看香蕉| 亚洲婷婷天堂综合国产剧情| 麻豆高潮AV久久久久久久| GAY东北澡堂激情2022| 十分钟免费看完整视频| 精品无码无人网站免费视频 | 午夜AV亚洲一码二中文字幕青青| 好紧好湿太硬了我太爽了小说| 97久久久久| 午夜福利32集云播| 免费看亚洲| 国产精品JIZZ视频免费| 中国xxxxxxxxx孕交| 十分钟免费视频大全在线观看| 久见久热 这里只有精品| 被公疯狂玩弄的漂亮人妻| 亚洲欧美中文字幕网站大全| 暖暖视频在线高清播放| 国产这里有精品| 啊轻点啊再深点视频免费| 亚洲人成网站在线观看90影院| 青草伊人久久| 久久天堂视频| 国产精品国产三级国产专区53| 69日本人XXXX护士HD| 亚洲 国产 日韩 欧美 在线| 欧美wwwvideos在线观看| 黄片在线观看| 国产99久久久国产精品成人| 91涩涩视频| 野草观看免费高清视频| 色翁荡熄月月| 欧美日韩另类在线专区| 久久天天婷婷五月俺也去| 国产亚洲精品久久精品6| 苍老师刺激的120分钟| 2022国产精品不卡a|