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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

c++ socket学习(1.4)

發(fā)布時間:2023/12/1 c/c++ 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++ socket学习(1.4) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本文學(xué)習(xí)相關(guān)資料:
C/C++ socket編程教程

環(huán)境:vs2015
源碼:本文代碼

前面學(xué)到了TCP怎么循環(huán)發(fā)包,但是TCP連接的話會出現(xiàn)一個問題粘包

TCP連接接收到的數(shù)據(jù)并不是馬上讀取到內(nèi)存里面的,而是放在緩沖區(qū),讓后調(diào)用recv函數(shù)來從緩沖區(qū)讀取數(shù)據(jù)。

當(dāng)然緩沖區(qū)是有大小限制

這時候就可能會出現(xiàn)粘包了。

1、假如客戶端發(fā)送的數(shù)據(jù)很少,但次數(shù)多;服務(wù)端一次讀取得多,就會將多次發(fā)送的內(nèi)容全部讀到一起。
2、假如一次客戶端發(fā)送的數(shù)據(jù)很多,服務(wù)端一次沒有讀取完,那么就會還有剩下的數(shù)據(jù)在緩沖區(qū);這時客戶端第二次發(fā)送數(shù)據(jù)過來,和前一次讀剩下的數(shù)據(jù)一起放。這時服務(wù)端又來讀取數(shù)據(jù)了,就會出現(xiàn)了第一次讀剩下的數(shù)據(jù)和第二次的部分?jǐn)?shù)據(jù)被服務(wù)端一起讀取。

來看看怎么實現(xiàn)這樣的情況

情況1:

服務(wù)端

int maxlen = 200; //接受客戶端的連接 SOCKET client = accept(servSock, (sockaddr*)&clntAddr, &nSize);while (1) {//通過sleep來讓客戶端信息全部發(fā)送到緩沖區(qū),讓服務(wù)器能夠一次讀取完Sleep(1000);//接受到信息int len = recv(client, buf, maxlen, 0);std::string s(buf);if (s.compare("exit") == 0) {std::cout << "接收到關(guān)閉信息,關(guān)閉服務(wù)器" << std::endl;break;}std::cout << s << " " << len << std::endl;}closesocket(client);

客戶端

int num = 5; connect(client, (sockaddr*)&servAddr, sizeof(sockaddr));std::string s("1234"); for (int i = 0; i < num; ++i)std::cout << send(client, s.c_str(), s.size(), 0) << std::endl;//注意不要把字符串最后面那個'\0'也發(fā)送了 send(client, "\0", 1, 0); //讓服務(wù)端先讀取完前面的內(nèi)容在發(fā)送結(jié)束 Sleep(4000); s = "exit"; std::cout << send(client, s.c_str(), s.size() + 1, 0) << std::endl;closesocket(client);

情況2:

服務(wù)端

int maxlen = 5; //注意這里不同了,表示服務(wù)端一次讀取得少 //接受客戶端的連接 SOCKET client = accept(servSock, (sockaddr*)&clntAddr, &nSize);while (1) {//通過sleep來讓客戶端信息全部發(fā)送到緩沖區(qū),讓服務(wù)器能夠一次讀取完//Sleep(1000); 睡眠也注釋了//接受到信息int len = recv(client, buf, maxlen, 0);std::string s(buf);if (s.compare("exit") == 0) {std::cout << "接收到關(guān)閉信息,關(guān)閉服務(wù)器" << std::endl;break;}std::cout << s << " " << len << std::endl;}closesocket(client);

客戶端

int num = 5; connect(client, (sockaddr*)&servAddr, sizeof(sockaddr));std::string s("12345679"); //這里不同了,表示客戶端一次發(fā)送得多 for (int i = 0; i < num; ++i)std::cout << send(client, s.c_str(), s.size(), 0) << std::endl;//注意不要把字符串最后面那個'\0'也發(fā)送了 send(client, "\0", 1, 0); //讓服務(wù)端先讀取完前面的內(nèi)容在發(fā)送結(jié)束,不然會讀到最后面那個'\0',和exit拼在了一起,就不會結(jié)束了 Sleep(4000); s = "exit"; std::cout << send(client, s.c_str(), s.size() + 1, 0) << std::endl;closesocket(client);

怎么解決粘包呢?
1、約定好每次讀取的數(shù)據(jù)長度,每次發(fā)送的數(shù)據(jù)長度,保證一次讀完
2、約定好每段發(fā)送數(shù)據(jù)的結(jié)束符,當(dāng)讀到這個結(jié)束符的時候表明讀取完了第一次發(fā)送的數(shù)據(jù),結(jié)束符后面的內(nèi)容屬于第二次發(fā)送的數(shù)據(jù)。

方法一比較簡單,就只是改個數(shù)值就可以了
來看看方法二要怎么做:

客戶端

int num = 5; connect(client, (sockaddr*)&servAddr, sizeof(sockaddr));std::string s("12345679A"); //這里確定每次發(fā)送的數(shù)據(jù)長度為10字節(jié),A表示數(shù)據(jù)結(jié)束 for (int i = 0; i < num; ++i)std::cout << send(client, s.c_str(), s.size(), 0) << std::endl; Sleep(4000); s = "exit"; std::cout << send(client, s.c_str(), s.size() + 1, 0) << std::endl;closesocket(client);

服務(wù)端

SOCKET client = accept(servSock, (sockaddr*)&clntAddr, &nSize); char temp[maxlen]; memset(temp, 0, sizeof(temp)); //通過sleep來讓客戶端信息全部發(fā)送到緩沖區(qū),讓服務(wù)器能夠一次讀取完 Sleep(1000);//表示讀取緩沖區(qū)的內(nèi)容的下標(biāo) int vBufSite = 0; int len = recv(client, buf, 7, 0); //一次讀7個字節(jié),肯定是要讀兩次的 while (1) {int vTempSite = 0;bool vRead = true;while (vRead) {if (vBufSite >=len) { //看看前一次讀取的內(nèi)容是不是包含了兩次發(fā)送的內(nèi)容len = recv(client, buf, 7, 0);vBufSite = 0;}while(vBufSite < len ) { //看看是不是包含了兩次發(fā)送的內(nèi)容if (buf[vBufSite] == 0) {vRead = false;temp[vTempSite] = 0;++vBufSite;break;}else if (buf[vBufSite] != 'A') { //讀到分隔符就結(jié)束temp[vTempSite++] = buf[vBufSite];++vBufSite;}else {vRead = false;temp[vTempSite] = 0;++vBufSite;break;}}}std::string s(temp);if (s.compare("exit") == 0) {std::cout << "接收到關(guān)閉信息,關(guān)閉服務(wù)器" << std::endl;break;}std::cout << s << std::endl;temp[0] = 0; } closesocket(client);

總結(jié)

以上是生活随笔為你收集整理的c++ socket学习(1.4)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。