RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Linux應(yīng)用開(kāi)發(fā)【第六章】網(wǎng)絡(luò)編程應(yīng)用開(kāi)發(fā)

weidongshan ? 來(lái)源:weidongshan ? 作者:weidongshan ? 2021-12-10 19:17 ? 次閱讀

文章目錄

6 網(wǎng)絡(luò)編程應(yīng)用開(kāi)發(fā)

6.1 網(wǎng)絡(luò)編程簡(jiǎn)介

6.1.1 五層因特網(wǎng)協(xié)議棧

6.1.2 傳輸層和應(yīng)用層的常見(jiàn)協(xié)議

6.2 網(wǎng)絡(luò)編程之TCP/UDP比較

6.2.1 TCP和UDP 原理上的區(qū)別

6.2.2 為何存在UDP協(xié)議

6.2.3 TCP/UDP網(wǎng)絡(luò)通信大概交互圖

6.3 網(wǎng)絡(luò)編程主要函數(shù)介紹

6.3.1 socket函數(shù)

6.3.2 bind函數(shù)

6.3.3 listen函數(shù)

6.3.4 accept函數(shù)

6.3.5 connect函數(shù)

6.3.6 send函數(shù)

6.3.7 recv函數(shù)

6.3.8 recvfrom函數(shù)

6.3.9 sendto函數(shù)

6.4 TCP編程簡(jiǎn)單示例

6.4.1 服務(wù)器端代碼

6.4.2 客戶(hù)端代碼

6.4.3 Makefile文件

6.4.4 執(zhí)行

6.5 UDP編程簡(jiǎn)單示例

6.5.1 服務(wù)器端代碼

6.5.2 客戶(hù)端代碼

6.5.2.1 客戶(hù)端程序1

6.5.2.2 客戶(hù)端程序2

6.5.3 Makefile文件

6.5.4 執(zhí)行

6 網(wǎng)絡(luò)編程應(yīng)用開(kāi)發(fā)

6.1 網(wǎng)絡(luò)編程簡(jiǎn)介

要編寫(xiě)通過(guò)計(jì)算機(jī)網(wǎng)絡(luò)通信的程序,首先要確定這些程序同通信的協(xié)議(protocol),在設(shè)計(jì)一個(gè)協(xié)議的細(xì)節(jié)之前,首先要分清程序是由哪個(gè)程序發(fā)起以及響應(yīng)何時(shí)產(chǎn)生。

舉例來(lái)說(shuō),一般認(rèn)為WEB服務(wù)器程序是一個(gè)長(zhǎng)時(shí)間運(yùn)行的程序(守護(hù)進(jìn)程deamon),它只在響應(yīng)來(lái)自網(wǎng)絡(luò)的請(qǐng)求時(shí)才發(fā)送網(wǎng)絡(luò)消息。協(xié)議的另一端是web客戶(hù)程序,如某種瀏覽器,與服務(wù)器進(jìn)程的通信總是由客戶(hù)進(jìn)程發(fā)起。大多數(shù)網(wǎng)絡(luò)應(yīng)用就是按照劃分為客戶(hù)(clinet)和服務(wù)器(server)來(lái)組織的。

6.1.1 五層因特網(wǎng)協(xié)議棧

為了給網(wǎng)絡(luò)協(xié)議的設(shè)計(jì)提供一個(gè)結(jié)構(gòu),網(wǎng)絡(luò)設(shè)計(jì)者以分層(layer)的方式組織協(xié)議以及實(shí)現(xiàn)這些協(xié)議的網(wǎng)絡(luò)硬件和軟件。

分層提供了一種結(jié)構(gòu)化方式來(lái)討論系統(tǒng)組件。模塊化使更新系統(tǒng)組件更為容易。

協(xié)議棧是各層所有協(xié)議的總和。

poYBAGGzNzWAdICbAAATy_4rwtM378.png

五層因特網(wǎng)協(xié)議棧

應(yīng)用層:應(yīng)用層是網(wǎng)絡(luò)應(yīng)用程序及它們的應(yīng)用層協(xié)議存留的地方。

運(yùn)輸層:因特網(wǎng)的運(yùn)輸層在應(yīng)用程序端點(diǎn)之間傳從應(yīng)用層報(bào)文。

網(wǎng)絡(luò)層:因特網(wǎng)呃網(wǎng)絡(luò)層負(fù)責(zé)將稱(chēng)為數(shù)據(jù)包(datagram)的網(wǎng)絡(luò)層分組從一臺(tái)主機(jī)移動(dòng)到另一臺(tái)主機(jī)。

鏈路層:因特網(wǎng)的網(wǎng)絡(luò)層通過(guò)源和目的地之間的一系列路由器路由數(shù)據(jù)報(bào)。

物理層:雖然鏈路層的任務(wù)是將整個(gè)幀從一個(gè)網(wǎng)絡(luò)元素移動(dòng)到臨近的網(wǎng)絡(luò)元素,而物理層的任務(wù)是將該幀的一個(gè)一個(gè)比特從一個(gè)節(jié)點(diǎn)移動(dòng)到下一個(gè)節(jié)點(diǎn)。

6.1.2 傳輸層和應(yīng)用層的常見(jiàn)協(xié)議

我們重點(diǎn)介紹和應(yīng)用層編程關(guān)系密切的應(yīng)用層和運(yùn)輸層。

應(yīng)用層:

因特網(wǎng)的應(yīng)用層包含很多協(xié)議,例如HTTP,SMTP,和 FTP。我們看到的某些網(wǎng)絡(luò)功能,比如將www.baidu.com這樣對(duì)人友好的端系統(tǒng)名字轉(zhuǎn)換為32比特網(wǎng)絡(luò)地址,也是借助于特定的應(yīng)用層協(xié)議即域名系統(tǒng)(DNS)完成的。

應(yīng)用層的協(xié)議分布在多個(gè)端系統(tǒng)上,一個(gè)端系統(tǒng)中的應(yīng)用程序使用協(xié)議與另一個(gè)端系統(tǒng)中的應(yīng)用程序交換信息分組。

運(yùn)輸層:

在英特網(wǎng)中有兩個(gè)運(yùn)輸協(xié)議,即TCP和UDP,利用其中的任何一個(gè)都能運(yùn)輸應(yīng)用層報(bào)文。我們寫(xiě)應(yīng)用程序的時(shí)候具體選擇哪個(gè)運(yùn)輸層協(xié)議應(yīng)該根據(jù)實(shí)際情況來(lái)確定(后面會(huì)具體講解)。

6.2 網(wǎng)絡(luò)編程之TCP/UDP比較

6.2.1 TCP和UDP 原理上的區(qū)別

TCP向它的應(yīng)用程序提供了面向連接的服務(wù)。這種服務(wù)包括了應(yīng)用層報(bào)文向目的地的確保傳遞和流量控制(即發(fā)送方/接收方速率匹配)。這種服務(wù)包括了應(yīng)用層報(bào)文劃分為短報(bào)文,并提供擁塞控制機(jī)制,因此當(dāng)網(wǎng)絡(luò)擁塞時(shí)源抑制其傳輸速率。

UDP協(xié)議向它的應(yīng)用程序提供無(wú)連接服務(wù)。這是一種不提供不必要服務(wù)的服務(wù),沒(méi)有可靠性,沒(méi)有流量控制,也沒(méi)有擁塞控制。

6.2.2 為何存在UDP協(xié)議

既然TCP提供了可靠數(shù)據(jù)傳輸服務(wù),而UDP不能提供,那么TCP是否總是首選呢?答案是否定的,因?yàn)橛性S多應(yīng)用更適合用UDP,原因有以下幾點(diǎn):

a. 關(guān)于何時(shí)發(fā)送什么數(shù)據(jù)控制的更為精細(xì)。

采用UDP時(shí)只要應(yīng)用進(jìn)程將數(shù)據(jù)傳遞給UDP,UDP就會(huì)立即將其傳遞給網(wǎng)絡(luò)層。而TCP有重傳機(jī)制,而不管可靠交付需要多長(zhǎng)時(shí)間。但是實(shí)時(shí)應(yīng)用通常不希望過(guò)分的延遲報(bào)文段的傳送,且能容忍一部分?jǐn)?shù)據(jù)丟失。

b. 無(wú)需建立連接,不會(huì)引入建立連接時(shí)的延遲。

c. 無(wú)連接狀態(tài),能支持更多的活躍客戶(hù)。

d. 分組首部開(kāi)銷(xiāo)較小。

6.2.3 TCP/UDP網(wǎng)絡(luò)通信大概交互圖

下面我們分別畫(huà)出運(yùn)用TCP協(xié)議和運(yùn)用UDP協(xié)議的客戶(hù)端和服務(wù)器大概交互圖。

pYYBAGGzNzuAa_SNAABSurUuxzU563.png

面向連接的TCP流模式

poYBAGGzN0GAaiaoAAAz9Vs51Gs694.png

UDP用戶(hù)數(shù)據(jù)包模式

6.3 網(wǎng)絡(luò)編程主要函數(shù)介紹

6.3.1 socket函數(shù)

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

此函數(shù)用于創(chuàng)建一個(gè)套接字。

domain是網(wǎng)絡(luò)程序所在的主機(jī)采用的通訊協(xié)族(AF_UNIX和AF_INET等)。

AF_UNIX只能夠用于單一的Unix 系統(tǒng)進(jìn)程間通信,而AF_INET是針對(duì)Internet的,因而可以允許遠(yuǎn)程通信使用。

type是網(wǎng)絡(luò)程序所采用的通訊協(xié)議(SOCK_STREAM,SOCK_DGRAM等)。

SOCK_STREAM表明用的是TCP 協(xié)議,這樣會(huì)提供按順序的,可靠,雙向,面向連接的比特流。

SOCK_DGRAM 表明用的是UDP協(xié)議,這樣只會(huì)提不可靠,無(wú)連接的通信。

關(guān)于protocol,由于指定了type,所以這個(gè)地方一般只要用0來(lái)代替就可以了。

此函數(shù)執(zhí)行成功時(shí)返回文件描述符,失敗時(shí)返回-1,看errno可知道出錯(cuò)的詳細(xì)情況。

6.3.2 bind函數(shù)

int bind(int sockfd, struct sockaddr *my_addr, int addrlen);

從函數(shù)用于將地址綁定到一個(gè)套接字。

sockfd是由socket函數(shù)調(diào)用返回的文件描述符。

my_addr是一個(gè)指向sockaddr的指針。

addrlen是sockaddr結(jié)構(gòu)的長(zhǎng)度。

sockaddr的定義:

struct sockaddr{ unisgned short as_family; char sa_data[14]; };

不過(guò)由于系統(tǒng)的兼容性,我們一般使用另外一個(gè)結(jié)構(gòu)(struct sockaddr_in) 來(lái)代替。

sockaddr_in的定義:

struct sockaddr_in{ unsigned short sin_family; unsigned short int sin_port; struct in_addr sin_addr; unsigned char sin_zero[8]; }

如果使用Internet所以sin_family一般為AF_INET。

sin_addr設(shè)置為INADDR_ANY表示可以和任何的主機(jī)通信。

sin_port是要監(jiān)聽(tīng)的端口號(hào)。

bind將本地的端口同socket返回的文件描述符捆綁在一起.成功是返回0,失敗的情況和socket一樣。

6.3.3 listen函數(shù)

int listen(int sockfd,int backlog);

此函數(shù)宣告服務(wù)器可以接受連接請(qǐng)求。

sockfd是bind后的文件描述符。

backlog設(shè)置請(qǐng)求排隊(duì)的最大長(zhǎng)度。當(dāng)有多個(gè)客戶(hù)端程序和服務(wù)端相連時(shí),使用這個(gè)表示可以介紹的排隊(duì)長(zhǎng)度。

listen函數(shù)將bind的文件描述符變?yōu)楸O(jiān)聽(tīng)套接字,返回的情況和bind一樣。

6.3.4 accept函數(shù)

int accept(int sockfd, struct sockaddr *addr,int *addrlen);

服務(wù)器使用此函數(shù)獲得連接請(qǐng)求,并且建立連接。

sockfd是listen后的文件描述符。

addr,addrlen是用來(lái)給客戶(hù)端的程序填寫(xiě)的,服務(wù)器端只要傳遞指針就可以了, bind,listen和accept是服務(wù)器端用的函數(shù)。

accept調(diào)用時(shí),服務(wù)器端的程序會(huì)一直阻塞到有一個(gè)客戶(hù)程序發(fā)出了連接。 accept成功時(shí)返回最后的服務(wù)器端的文件描述符,這個(gè)時(shí)候服務(wù)器端可以向該描述符寫(xiě)信息了,失敗時(shí)返回-1 。

6.3.5 connect函數(shù)

int connect(int sockfd, struct sockaddr * serv_addr,int addrlen);

可以用connect建立一個(gè)連接,在connect中所指定的地址是想與之通信的服務(wù)器的地址。

sockfd是socket函數(shù)返回的文件描述符。

serv_addr儲(chǔ)存了服務(wù)器端的連接信息,其中sin_add是服務(wù)端的地址。

addrlen是serv_addr的長(zhǎng)度

connect函數(shù)是客戶(hù)端用來(lái)同服務(wù)端連接的.成功時(shí)返回0,sockfd是同服務(wù)端通訊的文件描述符,失敗時(shí)返回-1。

6.3.6 send函數(shù)

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

sockfd指定發(fā)送端套接字描述符;

buf指明一個(gè)存放應(yīng)用程序要發(fā)送數(shù)據(jù)的緩沖區(qū);

len指明實(shí)際要發(fā)送的數(shù)據(jù)的字節(jié)數(shù);

flags一般置0。

客戶(hù)或者服務(wù)器應(yīng)用程序都用send函數(shù)來(lái)向TCP連接的另一端發(fā)送數(shù)據(jù)

6.3.7 recv函數(shù)

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

sockfd指定接收端套接字描述符;

buf指明一個(gè)緩沖區(qū),該緩沖區(qū)用來(lái)存放recv函數(shù)接收到的數(shù)據(jù);

len指明buf的長(zhǎng)度;

flags一般置0。

客戶(hù)或者服務(wù)器應(yīng)用程序都用recv函數(shù)從TCP連接的另一端接收數(shù)據(jù)。

6.3.8 recvfrom函數(shù)

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

recvfrom通常用于無(wú)連接套接字,因?yàn)榇撕瘮?shù)可以獲得發(fā)送者的地址。

src_addr是一個(gè)struct sockaddr類(lèi)型的變量,該變量保存源機(jī)的IP地址及端口號(hào)。

addrlen常置為sizeof (struct sockaddr)。

6.3.9 sendto函數(shù)

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);

sendto和send相似,區(qū)別在于sendto允許在無(wú)連接的套接字上指定一個(gè)目標(biāo)地址。

dest_addr表示目地機(jī)的IP地址和端口號(hào)信息,

addrlen常常被賦值為sizeof (struct sockaddr)。

sendto函數(shù)也返回實(shí)際發(fā)送的數(shù)據(jù)字節(jié)長(zhǎng)度或在出現(xiàn)發(fā)送錯(cuò)誤時(shí)返回-1。

6.4 TCP編程簡(jiǎn)單示例

服務(wù)器首先進(jìn)行初始化操作:調(diào)用函數(shù)socket創(chuàng)建一個(gè)套接字,函數(shù)bind將這個(gè)套接字與服務(wù)器的公認(rèn)地址綁定在一起,函數(shù)listen將這個(gè)套接字換成傾聽(tīng)套接字,然后調(diào)用函數(shù)accept來(lái)等待客戶(hù)機(jī)的請(qǐng)求。過(guò)了一段時(shí)間后,客戶(hù)機(jī)啟動(dòng),調(diào)用socket創(chuàng)建一個(gè)套接字,然后調(diào)用函數(shù)connect來(lái)與服務(wù)器建立連接。連接建立之后,客戶(hù)機(jī)和服務(wù)器通過(guò)讀、寫(xiě)套接字來(lái)進(jìn)行通信。

6.4.1 服務(wù)器端代碼

參考:TCP/server_line.c

1#include 2#include 3#include 4#include 5#include 6#include 7#include 8#include 9#include 10 11#define SERVER_PORT 8180 12#define C_QUEUE 10 13 14/************************************************************ 15*函數(shù)功能描述:從8180端口接收客戶(hù)端數(shù)據(jù) 16*輸入參數(shù):無(wú) 17*輸出參數(shù):打印客戶(hù)IP以及發(fā)來(lái)的信息 18*返回值:無(wú) 19*修改日期 版本號(hào) 修改人 修改內(nèi)容 20*2020/05/13 v1.0.0 zonghzha reat 21*************************************************************/ 22 23int main(int argc, char **argv) 24{ 25 char buf[512]; 26 int len; 27 int duty_socket; 28 int customer_socket; 29 struct sockaddr_in socket_server_addr; 30 struct sockaddr_in socket_client_addr; 31 int ret; 32 int addr_len; 33 34 signal(SIGCHLD, SIG_IGN); 35 36 /* 服務(wù)器端開(kāi)始建立socket描述符 */ 37 duty_socket = socket(AF_INET, SOCK_STREAM, 0); 38 if (duty_socket == -1) 39 { 40 printf("socket error"); 41 return -1; 42 } 43 44 /* 服務(wù)器端填充 sockaddr_in結(jié)構(gòu) */ 45 socket_server_addr.sin_family = AF_INET; 46 /* 端口號(hào)轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)序 */ 47 socket_server_addr.sin_port = htons(SERVER_PORT); 48 /* 接收本機(jī)所有網(wǎng)口的數(shù)據(jù) */ 49 socket_server_addr.sin_addr.s_addr = INADDR_ANY; 50 memset(socket_server_addr.sin_zero, 0, 8); 51 52 /* 捆綁sockfd描述符 */ 53 ret = bind(duty_socket, (const struct sockaddr *)&socket_server_addr, sizeof(struct sockaddr)); 54 if (ret == -1) 55 { 56 printf("bind error!n"); 57 return -1; 58 } 59 ret = listen(duty_socket, C_QUEUE); 60 if (ret == -1) 61 { 62 printf("listen error!n"); 63 return -1; 64 } 65 66 while (1) 67 { 68 addr_len = sizeof(struct sockaddr); 69 /* 服務(wù)器阻塞,直到客戶(hù)程序建立連接 */ 70 customer_socket = accept(duty_socket, (struct sockaddr *)&socket_client_addr, &addr_len); 71 if (customer_socket != -1) 72 { 73 /*inet_ntoa的作用是將一個(gè)32位Ipv4地址轉(zhuǎn)換為相應(yīng)的點(diǎn)分十進(jìn)制數(shù)串*/ 74 printf("Get connect from %sn", inet_ntoa(socket_client_addr.sin_addr)); 75 } 76 if (!fork()) 77 { 78 while (1) 79 { 80 memset(buf, 512, 0); 81 /*接收數(shù)據(jù)*/ 82 len = recv(customer_socket, buf, sizeof(buf), 0); 83 buf[len] = ''; 84 if (len <= 0) 85 { 86 close(customer_socket); 87 return -1; 88 } 89 else 90 { 91 printf("Get connect from %s, Msg is %sn", inet_ntoa(socket_client_addr.sin_addr), buf); 92 } 93 } 94 } 95 } 96 97 close(duty_socket); 98 return 0; 99}

6.4.2 客戶(hù)端代碼

參考:TCP/client_line.c

1#include 2#include 3#include 4#include 5#include 6#include 7#include 8#include 9 10#define SERVER_PORT 8180 11/************************************************************ 12*函數(shù)功能描述:向指定IP的8180端口發(fā)送數(shù)據(jù) 13*輸入?yún)?shù):點(diǎn)分十進(jìn)制服務(wù)器IP 14*輸出參數(shù):無(wú) 15*返回值:無(wú) 16*修改日期 版本號(hào) 修改人 修改內(nèi)容 17*2020/05/13 v1.0.0 zonghzha creat 18*************************************************************/ 19 20int main(int argc, char **argv) 21{ 22 unsigned char buf[512]; 23 int len; 24 struct sockaddr_in socket_server_addr; 25 int ret; 26 int addr_len; 27 int client_socket; 28 29 30 if (argc != 2) 31 { 32 printf("Usage:n"); 33 printf("%s n", argv[0]); 34 return -1; 35 } 36 37 /* 客戶(hù)程序開(kāi)始建立 sockfd描述符 */ 38 client_socket = socket(AF_INET, SOCK_STREAM, 0); 39 if (client_socket == -1) 40 { 41 printf("socket error"); 42 return -1; 43 } 44 45 /* 客戶(hù)程序填充服務(wù)端的資料 */ 46 socket_server_addr.sin_family = AF_INET; 47 /*主機(jī)字節(jié)序轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)序*/ 48 socket_server_addr.sin_port = htons(SERVER_PORT); 49 if (inet_aton(argv[1], &socket_server_addr.sin_addr) == 0) 50 { 51 printf("invalid server ipn"); 52 return -1; 53 } 54 memset(socket_server_addr.sin_zero, 0, 8); 55 /* 客戶(hù)程序發(fā)起連接請(qǐng)求 */ 56 ret = connect(client_socket, (const struct sockaddr *)&socket_server_addr, sizeof(struct sockaddr)); 57 if (ret == -1) 58 { 59 printf("connect error!n"); 60 return -1; 61 } 62 63 64 while (1) 65 { 66 if (fgets(buf, sizeof(buf), stdin)) 67 { 68 len = send(client_socket, buf, strlen(buf), 0); 69 if (len <= 0) 70 { 71 close(client_socket); 72 return -1; 73 } 74 } 75 } 76 77 close(client_socket); 78 return 0; 79}

6.4.3 Makefile文件

all:server client server:server.c gcc $^ -o $@ client:client.c gcc $^ -o $@ clean: rm server client -f (注意:命令語(yǔ)句的開(kāi)頭要用“Tab”鍵。)

6.4.4 執(zhí)行

服務(wù)器端:

./server

客戶(hù)端:

./client 127.0.0.1

客戶(hù)端輸入:

good night

服務(wù)器端顯示:

Get connect from 127.0.0.1 Get connect from 127.0.0.1, Msg is good night

6.5 UDP編程簡(jiǎn)單示例

UDP服務(wù)器首先進(jìn)行初始化操作:調(diào)用函數(shù)socket創(chuàng)建一個(gè)數(shù)據(jù)報(bào)類(lèi)型的套接字,函數(shù)bind將這個(gè)套接字與服務(wù)器的公認(rèn)地址綁定在一起。然后調(diào)用函數(shù)recvfrom接收UDP客戶(hù)機(jī)的數(shù)據(jù)報(bào)。UDP客戶(hù)機(jī)首先調(diào)用函數(shù)socket創(chuàng)建一個(gè)數(shù)據(jù)報(bào)套接字,然后調(diào)用函數(shù)sendto向服務(wù)器發(fā)送數(shù)據(jù)報(bào)。在結(jié)束通信后,客戶(hù)機(jī)調(diào)用close關(guān)閉UDP套接字,服務(wù)器繼續(xù)使用這個(gè)UDP套接字接收其它客戶(hù)機(jī)的數(shù)據(jù)報(bào)。

6.5.1 服務(wù)器端代碼

參考UDP/server_line.c

1#include 2#include 3#include 4//#include 5#include 6#include 7#include 8#include 9#include 10 11/*服務(wù)器端口為8180*/ 12#define SERVER_PORT 8180 13 14/************************************************************ 15*函數(shù)功能描述:從8180端口接收客戶(hù)端數(shù)據(jù) 16*輸入?yún)?shù):無(wú) 17*輸出參數(shù):打印客戶(hù)IP以及發(fā)來(lái)的信息 18*返回值:無(wú) 19*修改日期 版本號(hào) 修改人 修改內(nèi)容 20*2020/05/13 v1.0.0 zonghzha creat 21*************************************************************/ 22 23 24int main(int argc, char **argv) 25{ 26 unsigned char buf[512]; 27 int len; 28 int duty_socket; 29 int customer_socket; 30 struct sockaddr_in socket_server_addr; 31 struct sockaddr_in socket_client_addr; 32 int ret; 33 int addr_len; 34 35 /* 創(chuàng)建數(shù)據(jù)報(bào)套接字 */ 36 duty_socket = socket(AF_INET, SOCK_DGRAM, 0); 37 if (duty_socket == -1) 38 { 39 printf("socket error"); 40 return -1; 41 } 42 43 /* 服務(wù)器端填充 sockaddr_in結(jié)構(gòu) */ 44 socket_server_addr.sin_family = AF_INET; 45 socket_server_addr.sin_port = htons(SERVER_PORT); 46 socket_server_addr.sin_addr.s_addr = INADDR_ANY; 47 memset(socket_server_addr.sin_zero, 0, 8); 48 49 /*綁定套接字*/ 50 ret = bind(duty_socket, (const struct sockaddr *)&socket_server_addr, sizeof(struct sockaddr)); 51 if (ret == -1) 52 { 53 printf("bind error!n"); 54 return -1; 55 } 56 57 58 while (1) 59 { 60 addr_len = sizeof(struct sockaddr); 61 /* 接收客戶(hù)端數(shù)據(jù)報(bào),返回的為接收到的字節(jié)數(shù) */ 62 len = recvfrom(duty_socket, buf, sizeof(buf), 0, (struct sockaddr *)&socket_client_addr, &addr_len); 63 if (len > 0) 64 { 65 buf[len] = ''; 66 printf("Get Msg from %s : %sn", inet_ntoa(socket_client_addr.sin_addr), buf); 67 } 68 69 } 70 71 close(duty_socket); 72 return 0; 73} 74

6.5.2 客戶(hù)端代碼

6.5.2.1 客戶(hù)端程序1

參考UDP/client_line_1.c

1#include 2#include 3#include 4#include 5#include 6#include 7#include 8 9#define SERVER_PORT 8180 10 11/************************************************************ 12*函數(shù)功能描述:向指定IP的8180端口發(fā)送數(shù)據(jù) 13*輸入?yún)?shù):點(diǎn)分十進(jìn)制服務(wù)器IP 14*輸出參數(shù):無(wú) 15*返回值:無(wú) 16*修改日期 版本號(hào) 修改人 修改內(nèi)容 17*2020/05/13 v1.0.0 zonghzha creat 18*************************************************************/ 19 20int main(int argc, char **argv) 21{ 22 unsigned char buf[512]; 23 int len; 24 struct sockaddr_in socket_server_addr; 25 int ret; 26 int addr_len; 27 int client_socket; 28 29 30 if (argc != 2) 31 { 32 printf("Usage:n"); 33 printf("%s n", argv[0]); 34 return -1; 35 } 36 37 /*創(chuàng)建套接字*/ 38 client_socket = socket(AF_INET, SOCK_DGRAM, 0); 39 if (client_socket == -1) 40 { 41 printf("socket error"); 42 return -1; 43 } 44 45 /* 填充服務(wù)端的資料 */ 46 socket_server_addr.sin_family = AF_INET; 47 socket_server_addr.sin_port = htons(SERVER_PORT); 48 if (inet_aton(argv[1], &socket_server_addr.sin_addr) == 0) 49 { 50 printf("invalid server ipn"); 51 return -1; 52 } 53 memset(socket_server_addr.sin_zero, 0, 8); 54 55 56 57 58 while (1) 59 { 60 if (fgets(buf, sizeof(buf), stdin)) 61 { 62 // len = send(client_socket, buf, strlen(buf), 0); 63 /*向服務(wù)器端發(fā)送數(shù)據(jù)報(bào)*/ 64 addr_len = sizeof(struct sockaddr); 65 len = sendto(client_socket, buf, sizeof(buf), 0, (struct sockaddr *)&socket_server_addr, addr_len); 66 if (len <= 0) 67 { 68 close(client_socket); 69 return -1; 70 } 71 } 72 } 73 74 close(client_socket); 75 return 0; 76} 77

問(wèn):用UDP協(xié)議寫(xiě)網(wǎng)絡(luò)通訊程序不可以用connect函數(shù)嗎?

答:非也。

6.5.2.2 客戶(hù)端程序2

參考UDP/client_line_2.c

1#include 2#include 3#include 4#include 5#include 6#include 7#include 8 9/*服務(wù)器端口為8180*/ 10#define SERVER_PORT 8180 11 12/************************************************************ 13*函數(shù)功能描述:向指定IP的8180端口發(fā)送數(shù)據(jù) 14*輸入?yún)?shù):點(diǎn)分十進(jìn)制服務(wù)器IP 15*輸出參數(shù):無(wú) 16*返回值:無(wú) 17*修改日期 版本號(hào) 修改人 修改內(nèi)容 18*2020/05/13 v1.0.0 zonghzha creat 19*************************************************************/ 20 21int main(int argc, char **argv) 22{ 23 unsigned char buf[512]; 24 int len; 25 struct sockaddr_in socket_server_addr; 26 int ret; 27 int addr_len; 28 int client_socket; 29 30 31 if (argc != 2) 32 { 33 printf("Usage:n"); 34 printf("%s n", argv[0]); 35 return -1; 36 } 37 38 /*創(chuàng)建數(shù)據(jù)報(bào)套接字*/ 39 client_socket = socket(AF_INET, SOCK_DGRAM, 0); 40 if (client_socket == -1) 41 { 42 printf("socket error"); 43 return -1; 44 } 45 46 socket_server_addr.sin_family = AF_INET; 47 socket_server_addr.sin_port = htons(SERVER_PORT); 48 if (inet_aton(argv[1], &socket_server_addr.sin_addr) == 0) 49 { 50 printf("invalid server ipn"); 51 return -1; 52 } 53 memset(socket_server_addr.sin_zero, 0, 8); 54 55 ret = connect(client_socket, (const struct sockaddr *)&socket_server_addr, sizeof(struct sockaddr)); 56 if (ret == -1) 57 { 58 printf("connect error!n"); 59 return -1; 60 } 61 62 63 while (1) 64 { 65 if (fgets(buf, sizeof(buf), stdin)) 66 { 67 len = send(client_socket, buf, strlen(buf), 0); 68 if (len <= 0) 69 { 70 close(client_socket); 71 return -1; 72 } 73 } 74 } 75 76 close(client_socket); 77 return 0; 78} 79

在客戶(hù)端代碼2中,connect函數(shù)并非真的在協(xié)議層建立了連接,它只是指定了服務(wù)器的地址和端口號(hào)信息。

因?yàn)樵赾onnect中指定了服務(wù)器的地址和端口號(hào)信息,所以后面的send就可以直接發(fā)送了,而不用再次指定地址和端口號(hào)。

6.5.3 Makefile文件

all:server client_1 client_2 server:server.c gcc $^ -o $@ client_1:client_1.c gcc $^ -o $@ client_2:client_2.c gcc $^ -o $@ clean: rm server client_1 client_2 -f (注意:命令語(yǔ)句的開(kāi)頭要用“Tab”鍵。)

6.5.4 執(zhí)行

服務(wù)器端執(zhí)行:

./server

客戶(hù)端執(zhí)行:

./client_1 127.0.0.1

客戶(hù)端輸入:

good night

服務(wù)器端顯示:

Get Msg from 127.0.0.1 : good night

審核編輯 黃昊宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 網(wǎng)絡(luò)
    +關(guān)注

    關(guān)注

    14

    文章

    7553

    瀏覽量

    88729
  • 編程
    +關(guān)注

    關(guān)注

    88

    文章

    3614

    瀏覽量

    93686
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    《DNESP32S3使用指南-IDF版_V1.6》第六章 新建基礎(chǔ)工程

    第六章 新建基礎(chǔ)工程 在前面的章節(jié)中,我們已經(jīng)簡(jiǎn)要介紹了ESP32-S3的基礎(chǔ)知識(shí)和ESP-IDF的基本概念,并詳細(xì)闡述了VS Code IDE環(huán)境的搭建以及Espressif插件的安裝流程?,F(xiàn)在
    發(fā)表于 12-02 14:43

    Linux應(yīng)用編程的基本概念

    Linux應(yīng)用編程涉及到在Linux環(huán)境下開(kāi)發(fā)和運(yùn)行應(yīng)用程序的一系列概念。以下是一些涵蓋Linux應(yīng)用
    的頭像 發(fā)表于 10-24 17:19 ?222次閱讀

    【北京迅為】i.mx8mm嵌入式linux開(kāi)發(fā)指南第四篇 嵌入式Linux系統(tǒng)移植篇第六十九章uboot移植

    【北京迅為】i.mx8mm嵌入式linux開(kāi)發(fā)指南第四篇 嵌入式Linux系統(tǒng)移植篇第六十九章uboot移植
    的頭像 發(fā)表于 10-22 14:46 ?588次閱讀
    【北京迅為】i.mx8mm嵌入式<b class='flag-5'>linux</b><b class='flag-5'>開(kāi)發(fā)</b>指南第四篇 嵌入式<b class='flag-5'>Linux</b>系統(tǒng)移植篇<b class='flag-5'>第六</b>十九章uboot移植

    《DNK210使用指南 -CanMV版 V1.0》第六章 Kendryte K210固件燒錄

    第六章 Kendryte K210固件燒錄 本章將為讀者介紹Kendryte K210的固件燒錄,以及Kendryte K210外部NOR Flash的空間分布。本章分為如下幾個(gè)小節(jié):6.1 外部
    發(fā)表于 09-12 14:20

    【北京迅為】《stm32mp157開(kāi)發(fā)板嵌入式linux開(kāi)發(fā)指南》第五 Ubuntu使用apt-get下載

    【北京迅為】《stm32mp157開(kāi)發(fā)板嵌入式linux開(kāi)發(fā)指南》第五 Ubuntu使用apt-get下載
    的頭像 發(fā)表于 09-03 16:26 ?769次閱讀
    【北京迅為】《stm32mp157<b class='flag-5'>開(kāi)發(fā)</b>板嵌入式<b class='flag-5'>linux</b><b class='flag-5'>開(kāi)發(fā)</b>指南》第五<b class='flag-5'>章</b> Ubuntu使用apt-get下載

    linux開(kāi)發(fā)板與樹(shù)莓派的區(qū)別

    操作系統(tǒng)的微型計(jì)算機(jī),主要用于教育、編程、媒體播放等領(lǐng)域。 硬件配置 Linux開(kāi)發(fā)板:Linux開(kāi)發(fā)板的硬件配置因廠商和型號(hào)而異,通常包括
    的頭像 發(fā)表于 08-30 15:34 ?936次閱讀

    linux開(kāi)發(fā)板和單片機(jī)開(kāi)發(fā)的區(qū)別

    、PIC等,處理能力和內(nèi)存容量相對(duì)較低。 操作系統(tǒng) Linux開(kāi)發(fā)板通常使用Linux操作系統(tǒng),具有豐富的軟件資源和開(kāi)發(fā)工具。單片機(jī)開(kāi)發(fā)則通
    的頭像 發(fā)表于 08-30 15:30 ?728次閱讀

    Linux 驅(qū)動(dòng)開(kāi)發(fā)與應(yīng)用開(kāi)發(fā),你知道多少?

    一、Linux驅(qū)動(dòng)開(kāi)發(fā)與應(yīng)用開(kāi)發(fā)的區(qū)別開(kāi)發(fā)層次不同:Linux驅(qū)動(dòng)開(kāi)發(fā)主要是針對(duì)硬件設(shè)備進(jìn)行
    的頭像 發(fā)表于 08-30 12:16 ?747次閱讀
    <b class='flag-5'>Linux</b> 驅(qū)動(dòng)<b class='flag-5'>開(kāi)發(fā)</b>與應(yīng)用<b class='flag-5'>開(kāi)發(fā)</b>,你知道多少?

    SK海力士開(kāi)發(fā)第六代10納米級(jí)DDR5 DRAM

    SK海力士宣布了一項(xiàng)重大技術(shù)突破,成功開(kāi)發(fā)出全球首款采用第六代10納米級(jí)(1c)工藝的16Gb DDR5 DRAM。這一里程碑式的成就標(biāo)志著SK海力士在半導(dǎo)體存儲(chǔ)技術(shù)領(lǐng)域的領(lǐng)先地位。
    的頭像 發(fā)表于 08-29 16:39 ?667次閱讀

    【「ARM MCU嵌入式開(kāi)發(fā) | 基于國(guó)產(chǎn)GD32F10x芯片」閱讀體驗(yàn)】+書(shū)籍整體概況

    ,這里包含系統(tǒng)滴答定時(shí)器SysTick,RTC實(shí)時(shí)時(shí)鐘,看門(mén)狗(獨(dú)立看門(mén)狗與窗口看門(mén)狗),定時(shí)器(基本定時(shí)器、通用定時(shí)器、高級(jí)定時(shí)器),以及PWM實(shí)現(xiàn)呼吸燈效果實(shí)驗(yàn)。第六章為通用同步/異步串行通信
    發(fā)表于 08-25 22:48

    第六章-電機(jī)驅(qū)動(dòng)和PWM STM32項(xiàng)目

    萬(wàn)字筆記、12多個(gè)小時(shí)視頻、20多章節(jié)代碼手把手教會(huì)你如何開(kāi)發(fā)和調(diào)試。讓你更快掌握嵌入式系統(tǒng)開(kāi)發(fā)。** V3.3.0-STM32智能小車(chē) 視頻: https
    的頭像 發(fā)表于 08-21 16:46 ?614次閱讀
    <b class='flag-5'>第六章</b>-電機(jī)驅(qū)動(dòng)和PWM STM32項(xiàng)目

    雙麒麟系統(tǒng)!迅為RK3588開(kāi)發(fā)板+銀河麒麟/開(kāi)放麒麟

    Build root系統(tǒng)功能測(cè)試 第四 Ubuntu系統(tǒng)功能測(cè)試 第五 Debian系統(tǒng)功能測(cè)試 第六章 openkylin系統(tǒng)功能測(cè)試 第七 銀河麒麟系統(tǒng)功能測(cè)試
    發(fā)表于 07-15 10:35

    第3_UART 開(kāi)發(fā)基礎(chǔ)

    第3_UART 開(kāi)發(fā)基礎(chǔ)
    的頭像 發(fā)表于 06-29 14:27 ?674次閱讀
    第3<b class='flag-5'>章</b>_UART <b class='flag-5'>開(kāi)發(fā)</b>基礎(chǔ)

    搭配100教學(xué)實(shí)驗(yàn)案例,輕松解決老師備課難題!

    Linux系統(tǒng)使用實(shí)驗(yàn)第三Linux設(shè)備驅(qū)動(dòng)程序開(kāi)發(fā)實(shí)驗(yàn)第四基于ARM基礎(chǔ)外設(shè)實(shí)驗(yàn)第五Li
    的頭像 發(fā)表于 05-01 08:31 ?401次閱讀
    搭配100教學(xué)實(shí)驗(yàn)案例,輕松解決老師備課難題!

    fpga開(kāi)發(fā)板與linux開(kāi)發(fā)板區(qū)別

    (Field-Programmable Gate Array)是一種可編程邏輯器件,它可以通過(guò)編程改變硬件邏輯電路的功能和結(jié)構(gòu)。FPGA采用了可編程的門(mén)極,可以根據(jù)需要重新配置內(nèi)部電路,從而實(shí)現(xiàn)不同的功能和邏輯關(guān)系。而
    的頭像 發(fā)表于 02-01 17:09 ?2227次閱讀
    RM新时代网站-首页