C++ Socket

Socket網(wǎng)絡(luò)編程實現(xiàn)過程簡單總結(jié)

一、? ?服務(wù)器端

1、? ? 加載及釋放套接字庫

a)? ? ? ?使用函數(shù)WSAStartup()綁定相應(yīng)的套接字庫:

????當(dāng)一個應(yīng)用程序調(diào)用WSAStartup函數(shù)時,操作系統(tǒng)根據(jù)請求的Socket版本來搜索相應(yīng)的Socket庫,然后綁定找到的Socket庫到該應(yīng)用程序中。以后應(yīng)用程序就可以調(diào)用所請求的Socket庫中的其它Socket函數(shù)了。該函數(shù)執(zhí)行成功后返回0。

Ex:

????????wVersionRequested = MAKEWORD( 2, 1 );//指定加載2.1版本

? ? ? ? err =WSAStartup( wVersionRequested, &wsaData );

關(guān)于Socket版本:不同版本是有區(qū)別的,例如1.1版只支持TCP/IP協(xié)議,而2.0版可以支持多協(xié)議。2.0版有良好的向后兼容性,任何使用1.1版的源代碼、二進制文件、應(yīng)用程序都可以不修改地在2.0規(guī)范下使用。此外winsock 2.0支持異步 1.1不支持異步.

b)? ?使用函數(shù)WSACleanup ()綁定相應(yīng)的套接字庫:

應(yīng)用程序在完成對請求的Socket庫的使用后,要調(diào)用WSACleanup函數(shù)來解除與Socket庫的綁定并且釋放Socket庫所占用的系統(tǒng)資源。

c)? ? 以上二者需要庫Ws2_32.lib和頭文件winsock2.h

#include"winsock2.h"

#pragma comment(lib,”ws2_32.lib”)

2、? ?創(chuàng)建套接字

socket(domain=AF_INET,type=SOCK_STREAM,proto=IPPROTO_TCP)

三個參數(shù)分別是:地址系列,套接字類型,協(xié)議號

1)、Domain : Domain參數(shù)指定了通信的”域”

AF_UNIX :AF_LOCAL本地通信

AF_INET:IPv4網(wǎng)絡(luò)通信

AF_INET6:IPv6網(wǎng)絡(luò)通信

AF_PACKET:鏈路層通信

2)、Type: Type就是socket的類型,對于AF_INET協(xié)議族而言有流套接字(SOCK_STREAM)、數(shù)據(jù)包套接字(SOCK_DGRAM)、原始套接字(SOCK_RAW)。

????????SOCK_STREAM:流套接字, 提供順序,可靠,雙向,基于連接的字節(jié)流。 可以支持帶外數(shù)據(jù)傳輸機制。例

????????????如:TCP協(xié)議、FTP協(xié)議

????????SOCK_DGRAM:數(shù)據(jù)包套接字, 支持數(shù)據(jù)報(無連接,不可靠的固定最大長度的消息)例如:UDP協(xié)議

????????SOCK_RAW:原始套接字, 使用原始套接字時候調(diào)用,原始套接字也就是鏈路層協(xié)議

????????SOCK_SEQPACKET:有序分組套接字,為固定最大長度的數(shù)據(jù)報提供有序,可靠,雙向連接的數(shù)據(jù)傳輸路徑; 消費者需要利用每個輸入系統(tǒng)調(diào)用讀取整個分組

3)、Protocol:支持的協(xié)議

參數(shù)解析參考:https://blog.csdn.net/liuxingen/article/details/44995467

3、? 綁定服務(wù)器套接字地址

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

服務(wù)端套接字綁定自己的IP地址與端口號,客戶端那邊可以不寫,內(nèi)核會給它分配一個臨時的端口。

參數(shù):

1)、sockfd: 服務(wù)器或者客戶端自己創(chuàng)建的socket

2)、sockaddr: 服務(wù)器或者客戶端自己的地址信息(協(xié)議族、IP、端口號)

sockaddr 與sockaddr_in:

二者的占用的內(nèi)存大小是一致的,因此可以互相轉(zhuǎn)化,從這個意義上說,他們并無區(qū)別。

sockaddr常用于bind、connect、recvfrom、sendto等函數(shù)的參數(shù),指明地址信息。是一種通用的套接字地址。而sockaddr_in 是internet環(huán)境下套接字的地址形式。所以在網(wǎng)絡(luò)編程中我們會對sockaddr_in結(jié)構(gòu)體進行操作。使用sockaddr_in來建立所需的信息,最后使用類型轉(zhuǎn)化就可以了。

3)、socklen_t: 服務(wù)器或者客戶端自己的地址信息的長度

EXP:

seraddr.sin_family = AF_INET; // 設(shè)置地址族為IPv4

seraddr.sin_port = htons(SERPORT);??? //設(shè)置地址的端口號信息

seraddr.sin_addr.s_addr = inet_addr(SERADDR);?? // 設(shè)置IP地址

ret= bind(sockfd, (const struct sockaddr *)&seraddr, sizeof(seraddr));

參考:https://blog.csdn.net/zz709196484/article/details/54864770

4、? ? 將套接字設(shè)置為監(jiān)聽模式等待連接請求

intlisten(int? sockfd, int? backlog);

用法:函數(shù)應(yīng)該在調(diào)用socket和bind這兩個函數(shù)之后,accept函數(shù)之前調(diào)用。

作用:讓服務(wù)器套接字sockfd進入監(jiān)聽狀態(tài)。

參數(shù):sockfd:套接字,成功返回后進入監(jiān)聽模式,當(dāng)有新連接并accept后會再建立一個套接字保存新的連接;

? backlog:并發(fā)連接數(shù),下面詳細介紹此參數(shù):

????????1)? 當(dāng)TCP接收一個連接后(三次握手通過)會將此連接存在連接請求隊列里面,并對隊列個數(shù)+1,而backlog為此隊列允許的最大個數(shù),超過此值,則直接將新的連接刪除,即不在接收新的連接。將這些處于請求隊列里面的連接暫記為后備連接,這些都在底層自動完成,底層將連接添加到隊列后等待上層來處理(一般是調(diào)用accept函數(shù)接收連接);

????????2)? 當(dāng)上層調(diào)用accept函數(shù)接收一個連接(處于請求隊列里面的后備連接),隊列個數(shù)會-1;

????????3)? 那么這樣一個加一個減,只要底層提交的速度小于上層接收的速度(一般是這樣),很明顯backlog就不能限制連接的個數(shù),只能限制后備連接的個數(shù)。那為啥要用這個backlog呢?主要用于并發(fā)處理,當(dāng)上層沒來的及接收時,底層可以提交多個連接;

????????4)?backlog的取值范圍 ,一般為0-5。

5、? ?接受連接請求,返回一個新的對應(yīng)于此次連接的套接字

????????accept(intsocket, sockaddr *name, int *addrlen)

??????? 參數(shù)socket: 是一個已設(shè)為監(jiān)聽模式的服務(wù)器端socket的描述符。

??????? 參數(shù)sockaddr: 是一個返回值,它指向一個struct sockaddr類型的結(jié)構(gòu)體的變量,保存了發(fā)起連接的客戶端得IP地址信息和端口信息。

??????? 參數(shù)addrlen: 也是一個返回值,指向整型的變量,保存了返回的地址信息的長度。

???????accept函數(shù)返回值是一個客戶端和服務(wù)器連接的SOCKET類型的描述符,在服務(wù)器端標識著這個客戶端。

6、? ?用5返回的套接字和客戶端進行通信(send()/recv());

send(sockets, char * str, int len, int flag)

??????? 第一個參數(shù):本機創(chuàng)建的套接字

??????? 第二個參數(shù):要發(fā)送的字符串

??????? 第三個參數(shù):發(fā)送字符串長度

??????? 第四個參數(shù):會對函數(shù)行為產(chǎn)生影響,一般設(shè)置為0

??? recv(socket s, char * buf, int len,intflag)

??????? 參數(shù)socket:創(chuàng)建的可以傳輸消息過來的套接字

??????? 參數(shù)buf:接受消息的字符串緩存

??????? 參數(shù)len:允許接收字符串的緩存的最大長度

? ? ? ? 第四個參數(shù):會對函數(shù)行為產(chǎn)生影響,一般設(shè)置為0

send和recv實際上分別是write和read函數(shù)的基礎(chǔ)上擴展了第四個參數(shù):

1)、recv對應(yīng)的flags有3個選項:

??? MSG_PEEK:查看數(shù)據(jù),并不從系統(tǒng)緩沖區(qū)移走數(shù)據(jù)

??? MSG_WAITALL:等待所有數(shù)據(jù),等到所有的信息到達時才返回,使用它時,recv返回一直阻塞,直到指定的條件滿足時,或者發(fā)生錯誤

? ? ?MSG_OOB:接受或者發(fā)送帶外數(shù)據(jù)

2)、send第四個參數(shù)flags,有2個選項:

??? MSG_DONTROUTE:不查找表,它告訴ip,目的主機在本地網(wǎng)絡(luò)上,沒必要查找表。(一般用在網(wǎng)絡(luò)診斷和路由程序里面)

? ? MSG_OOB:接受或者發(fā)送帶外數(shù)據(jù)?

功能上是分別將SendBuff拷貝到發(fā)送緩沖區(qū)中和將接受緩沖區(qū)的數(shù)據(jù)拷貝到ReciveBuf中;

https://blog.csdn.net/tingyun_say/article/details/51907687

https://blog.csdn.net/rankun1/article/details/50488989

二、? 客戶端

1、加載套接字庫,創(chuàng)建套接字(WSAStartup()/socket());

2、向服務(wù)器發(fā)出連接請求(connect());

3、和服務(wù)器進行通信(send()/recv());

4、關(guān)閉套接字,關(guān)閉加載的套接字庫(closesocket()/WSACleanup());

三、? 代碼實現(xiàn)

環(huán)境:window7、vs2015

服務(wù)器端:

#include<iostream>

#include "winsock2.h"

#pragma comment(lib,"ws2_32.lib")

using namespace std;

int main()

{

????int RetVal;

????WORD SocketVersion=MAKEWORD(2, 2);

????WSADATA wsd;

????if (WSAStartup(SocketVersion, &wsd) != 0)

????{

????????cout << "綁定Socket庫失敗" << endl;

????}

????SOCKET ServerSocket;

????ServerSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

????if (ServerSocket == INVALID_SOCKET)

????{

????????cout << "創(chuàng)建服務(wù)器套接字失敗" << endl;

????????WSACleanup();

????????return -1;

}

SOCKADDR_IN ServerAddr;

ServerAddr.sin_family = AF_INET;

ServerAddr.sin_port = htons(2345);

ServerAddr.sin_addr.S_un.S_addr = INADDR_ANY;

RetVal = bind(ServerSocket, (SOCKADDR *)&ServerAddr, sizeof(SOCKADDR_IN));

if (RetVal == SOCKET_ERROR)

{

????cout << "套接字綁定失敗" << endl;

????closesocket(ServerSocket);

????WSACleanup();

????return -1;

}

RetVal = listen(ServerSocket,2);

if (RetVal == SOCKET_ERROR)

{

????cout << "套接字監(jiān)聽失敗" << endl;

????closesocket(ServerSocket);

????WSACleanup();

????return -1;

}

SOCKET ClientSocket;

SOCKADDR_IN ClientAddr;

int ClientAddrLen = sizeof(ClientAddr);

ClientSocket = accept(ServerSocket, (SOCKADDR*)&ClientAddr, &ClientAddrLen);

if (ClientSocket == INVALID_SOCKET)

{

????cout << "接收客戶端請求失敗" << endl;

????closesocket(ServerSocket);

????WSACleanup();

????return -1;

}

char ReceiveBuff[BUFSIZ];

char SendBuff[BUFSIZ];

while (true)

{

????ZeroMemory(ReceiveBuff, BUFSIZ);

????RetVal = recv(ClientSocket, ReceiveBuff, BUFSIZ, 0);

????if (RetVal == SOCKET_ERROR)

????{

????????cout << "接收數(shù)據(jù)失敗" << endl;

????????closesocket(ServerSocket);

????????closesocket(ClientSocket);

???????WSACleanup();

????????return? -1;

????}

cout << "接收自客戶端數(shù)據(jù):" << ReceiveBuff << endl;

cout << "向客戶端發(fā)送數(shù)據(jù):";

cin >> SendBuff;

send(ClientSocket, SendBuff, strlen(SendBuff), 0);

}

closesocket(ServerSocket);

closesocket(ClientSocket);

WSACleanup();

return 0;

}

客戶端:

#include<iostream>

#include "winsock2.h"

#pragma comment(lib,"ws2_32.lib")

using namespace std;

int main()

{

????const int BUF_SIZE = 64;

????int RetVal;

????WSADATA Wsd;

????if (WSAStartup(MAKEWORD(2, 2), &Wsd) != 0)

????{

????????cout << "初始化套接字動態(tài)庫失敗" << endl;

????????return -1;

????}

????SOCKET ServerScoket;

????ServerScoket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

????if (ServerScoket == INVALID_SOCKET)

????{

????????cout << "創(chuàng)建套接字失敗" << endl;

????????WSACleanup();

????????return -1;

????}

????SOCKADDR_IN ServerAddr;

????ServerAddr.sin_family = AF_INET;

????ServerAddr.sin_port = htons(2345);

????ServerAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

????RetVal = connect(ServerScoket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr));

????if (RetVal == SOCKET_ERROR)

????{

????????cout << "鏈接服務(wù)器失敗" << endl;

????????closesocket(ServerScoket);

????????WSACleanup();

????????return -1;

????}

????char SendBuff[BUF_SIZE];

????char RECVBuff[BUF_SIZE];

????while (true)

????{

????????ZeroMemory(SendBuff, BUF_SIZE);

????????cout << "向服務(wù)器發(fā)送數(shù)據(jù)" << endl;

????????cin >> SendBuff;

????????RetVal = send(ServerScoket, SendBuff, strlen(SendBuff),0);

????????if (RetVal == SOCKET_ERROR)

????????{

????????????cout << "發(fā)送數(shù)據(jù)失敗" << endl;

????????????closesocket(ServerScoket);

????????????WSACleanup();

????????????return -1;

????????}

????ZeroMemory(RECVBuff, BUF_SIZE);

????recv(ServerScoket, RECVBuff, BUF_SIZE, 0);

????cout << endl << "從服務(wù)器接收數(shù)據(jù):" << RECVBuff << endl;

????}

????closesocket(ServerScoket);

????WSACleanup();

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,746評論 2 370

推薦閱讀更多精彩內(nèi)容

  • socket通信原理 socket又被叫做套接字,它就像連接到兩端的插座孔一樣,通過建立管道,將兩個不同的進程之間...
    jiodg45閱讀 1,162評論 0 1
  • IP地址操作類 IPAddress類在該類中有一個Parse()方法,可以把點分的十進制IP轉(zhuǎn)化成IPAddres...
    Lv1_Sans閱讀 4,495評論 0 3
  • 1三個相關(guān)數(shù)據(jù)結(jié)構(gòu). 關(guān)于socket的創(chuàng)建,首先需要分析socket這個結(jié)構(gòu)體,這是整個的核心。 104 str...
    ice_camel閱讀 2,858評論 1 8
  • 刺眼的陽光,喧鬧的茶座,暑假開始一半的七月要結(jié)束了。許久未見的閨蜜剛剛走,獨自坐在長椅上的我便有些悵然若失。其實我...
    幕夏景涼閱讀 285評論 0 0
  • 【導(dǎo)讀】過年回去去了別人家,感覺與自己家有很大不同,這就好像去了不同的城市的那種感受,不知道你是不是也有這種感覺。...
    春未央閱讀 468評論 0 2