日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【Socket网络编程】16.UDP 循环读取recvfrom() 与 循环发送 sendto()

發布時間:2025/3/21 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Socket网络编程】16.UDP 循环读取recvfrom() 与 循环发送 sendto() 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

@zhz:

疑問:有時候會看到某些代碼,sendto()時用了while循環, 而recvfrom()時沒使用while循環?

答:他們都可以使用循環語句,可參考TCP數據粘包的處理。

什么時候需要使用循環,什么時候不使用循環,可以看下面的分析:

以下其實是我根據自己項目使用的udp協議中的recvfrom()和sendto()進行測試沒問題后分析的。但是對于TCP粘包的問題,卻并非如此,并非recv每次只取一次完整發送的數據(UDP的recvfrom()為什么可以取這么準?),我目前還沒測試。
1. recvfrom()要使用與不使用循環的情況:

我們通常指定的接收端一次接收長度都會 >= 發送端一次發送的數據長度。通常情況下,我們發送端一次發送的數據長度都不會是固定的,所以就需要接收端設置一個合適的固定的接收長度,這個固定長度需要大于等于發送端一次發送的最大數據長度。

當recvfrom()函數指定buf的長度后,并且一次recvfrom()函數讀取到的數據小于指定長度max_length(這個是可以保證的),那么:

  • 如果能確定每次recvfrom()實際讀取到的數據是發送端一次發送的完整數據,那就不用循環recvfrom()。
  • 如果每次recvfrom()實際讀取到的數據不是發送端一次發送的完整數據,就需要循環recvfrom()。

2.sendto()要使用與不使用循環的情況:

sendto()一般情況下需要使用循環,因為假如一個數據包太大,如長度為10MB,一次sendto()發送到輸出緩沖區可能發不完整,此時就需要對sendto()使用循環發送,直到把10MB的數據都拷貝到輸出緩沖區。
sendto()函數中參數指定的數據長度,就是本次發送(就是寫入輸出緩沖區)的數據長度,都會提前計算好之后再填入,每次發送的數據長短可能不一樣,所以他就不是固定長度的。
而recvfrom()函數中指定的長度是固定的。


3.recvfrom()和sendto()例子:

recvfrom()和sendto()的第三個參數len都是指定第二個參數buf的長度。

  • 1.recvfrom()從輸入緩沖區中拷貝數據到應用程序緩沖區buf,在此需要指定buf的長度。他的長度一般在定義緩沖buf時就定下來了,如
constexpr std::size_t kBufferSize = 1024; ... uint8_t buf[kBufferSize] = {0}; //定義buf時,長度也定下來了 std::memset(buf, 0, kBufferSize); ... length = data_stream_->read(buf, kBufferSize, 0); 上面的read()函數會調用: ret = ::recvfrom(sockfd_, buffer, kBufferSize, 0)
  • 2.sendto()從輸出緩沖區中拷貝數據到應用程序緩沖區buf,在此需要指定buf的長度。他的長度都會提前計算好之后再填入,每次發送的數據長短可能不一樣,所以他就不是固定長度的:
constexpr std::size_t kBufferSize = 1024;char buf[kBufferSize] = "abcd"; // proto_msg_是一個已經賦值后的protobuf消息的變量int proto_msg_length = proto_msg_.ByteSize(); // 把 proto_msg_ 序列化進buf,從buf第四字節開始,前四個字節為"cidi"proto_msg_.SerializeToArray(&buf[4], proto_msg_length);int send_size = proto_msg_length + 4; // 加上"cidi"四個字節// 雖然 buf有1024字節,但是只將他的前 send_size 字節寫入輸出緩沖區std::size_t len = data_stream_->write(reinterpret_cast<uint8_t*>(buf),send_size, 0);上面的write()函數會調用: ret = ::sendto(sockfd_, buffer, kBufferSize, 0)

sendto()
size_t UdpStream::write(const uint8_t* data, size_t length, uint8_t flag) {size_t total_nsent = 0;// if (flag) {// peer_sockaddr_.sin_addr.s_addr = htonl(INADDR_BROADCAST);// }peer_sockaddr_.sin_addr.s_addr = peer_addr_;peer_sockaddr_.sin_port = peer_broad_port_;SDEBUG << "sendto addr: " << inet_ntoa(peer_sockaddr_.sin_addr)<< ", port: " << ntohs(peer_sockaddr_.sin_port);while (length > 0) {ssize_t nsent =::sendto(sockfd_, data, length, 0, (struct sockaddr*)&peer_sockaddr_,(socklen_t)sizeof(peer_sockaddr_));if (nsent < 0) { // errorif (errno == EINTR) {continue;} else {// errorif (errno == EPIPE || errno == ECONNRESET) {status_ = Stream::Status::DISCONNECTED;errno_ = errno;} else if (errno != EAGAIN) {status_ = Stream::Status::ERROR;errno_ = errno;}return total_nsent;}}total_nsent += nsent;length -= nsent;data += nsent;}return total_nsent; }
recvfrom()
size_t UdpStream::read(uint8_t* buffer, size_t max_length, uint8_t flag) {ssize_t ret = 0;struct sockaddr_in addrfrom;addrfrom.sin_addr.s_addr = htonl(INADDR_ANY);if (flag) {peer_sockaddr_.sin_addr.s_addr = htonl(INADDR_ANY);} else {addrfrom.sin_addr.s_addr = peer_sockaddr_.sin_addr.s_addr;}while ((ret = ::recvfrom(sockfd_, buffer, max_length, 0,(struct sockaddr*)&peer_sockaddr_,reinterpret_cast<socklen_t*>(&socklenth_))) < 0) {if (errno == EINTR) {continue;} else {// errorif (errno != EAGAIN) {status_ = Stream::Status::ERROR;errno_ = errno;}}return 0;}// 接收來自本車obu的數據包:0x63,0x69,0x64,0x69分別表示cidi的ASCII碼:99,105,100,105// 如果不是"cidi",1.如果是單播,就把ip保持為上一次成功單播的ip;// 2.如果是廣播,就把ip設為0.0.0.0(即htonl(INADDR_ANY)),即本機任意網卡的ipif (0x63 != buffer[0] && 0x69 != buffer[1] &&0x64 != buffer[2] && 0x69 != buffer[3]) {peer_sockaddr_.sin_addr.s_addr = addrfrom.sin_addr.s_addr;}// // 0x60,0x61 分別對應'`'和'a'的ASCII碼 96(`),97(a)// if (buffer[0] != 0x60 && buffer[1] != 0x61) {// peer_sockaddr_.sin_addr.s_addr = addrfrom.sin_addr.s_addr;// }SDEBUG << "Receive addr: " << inet_ntoa(peer_sockaddr_.sin_addr)<< ", port: " << ntohs(peer_sockaddr_.sin_port);return ret; }

總結

以上是生活随笔為你收集整理的【Socket网络编程】16.UDP 循环读取recvfrom() 与 循环发送 sendto()的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 欧美激情一区二区 | 精品成人中文无码专区 | 久久精品国产精品亚洲毛片 | 欧美熟妇精品一区二区 | 91中文 | 性——交——性——乱免费的 | 蜜臀在线播放 | 天堂а在线中文在线新版 | 高跟av | 大尺度摸揉捏胸床戏视频 | 网站黄在线 | 久久国产精品久久久 | 日本高清视频在线播放 | 不卡av电影在线 | 一区二区精品久久 | 99久久久国产精品无码免费 | 日日日人人人 | 国产精品久久国产精品 | 香港三级日本三级韩国三级 | 国内成人免费视频 | 风间由美一区二区 | 高清av网址| 喷水在线观看 | 成人激情视频网站 | 先锋资源av网 | 粉嫩一区二区三区 | 豆花在线视频 | 免费国产视频在线观看 | 亚州中文字幕 | 久久久999视频 | 久久久ww | 夜噜噜| 桃色在线视频 | 一个人在线观看www www.97色 | 成人欧美一区二区三区黑人孕妇 | 可以看的黄色网 | 狠狠干青青草 | 亚洲喷水| 久久久久99精品成人片试看 | 国产精品自产拍高潮在线观看 | 日韩一级特黄 | 色伊人 | 欧美日韩一级二级 | 高清乱码免费看污 | 2019av视频| 亚洲精品一区二区三区在线 | 亚洲精品无码久久久久久久 | 日韩亚洲欧美在线 | 天天操夜夜操 | 免费视频a | 国产高清久久久 | 亚洲自拍中文 | 东方伊甸园av在线 | 一个色在线视频 | 可以在线观看的黄色 | 欧美激情精品久久久久久蜜臀 | 黄色福利在线观看 | 欧美多p | 五月婷婷久久综合 | 久久99精品久久久久久 | 91在线视频网址 | 亚洲伦理在线播放 | 亚洲第8页 | 久久久久久久综合色一本 | 天天干夜夜夜 | 五月深爱网 | 日韩欧美一区二区三区在线 | 亚洲天堂av网站 | 国精产品一区一区三区有限公司杨 | 久久在线视频精品 | 97青青草 | 国产精品蜜臀 | 丁香婷婷网 | 好吊妞精品 | 深夜在线免费视频 | 91porny丨首页入口在线 | a黄色片 | 欧美成人免费在线 | 日韩精品在线视频 | 福利一区二区在线观看 | 爱情岛论坛自拍亚洲品质极速最新章 | 亚洲天堂成人 | 黄色裸体网站 | 91免费在线| 欧美理伦少妇2做爰 | 欧美一级大片 | 中国极品少妇xxxx做受 | 最近国语视频在线观看免费播放 | 久久久久无码国产精品 | 国产精品日本 | 污视频在线播放 | 久久综合亚洲色hezyo国产 | 欧美高清v | 精品免费在线 | 国产二区一区 | 国产私人影院 | 国产伦精品一区二区三区视频我 | 欧美精品系列 | 天天爱天天干天天操 |