Windows socket c++ TCP UDP 简单客户端 vs2013
socket 主要是網(wǎng)絡(luò)中進(jìn)程之間的通信,起源于Unix,而“一切皆可文件”的思想一樣可以用在socket上,即 打開(kāi) -> 讀寫 -> 關(guān)閉。
int socket(int domain, int type, int protocol):(服務(wù)端 & 客戶端)
socket函數(shù)對(duì)應(yīng)于普通文件的打開(kāi)操作。普通文件的打開(kāi)操作返回一個(gè)文件描述字,而socket()用于創(chuàng)建一個(gè)socket描述符(socket descriptor),它唯一標(biāo)識(shí)一個(gè)socket。
這個(gè)socket描述字跟文件描述字一樣,后續(xù)的操作都有用到它,把它作為參數(shù),通過(guò)它來(lái)進(jìn)行一些讀寫操作。
- domain:即協(xié)議域,又稱為協(xié)議族(family)。常用的協(xié)議族有,AF_INET、AF_INET6、AF_LOCAL(或稱AF_UNIX,Unix域socket)、AF_ROUTE等等。協(xié)議族決定了socket的地址類型,在通信中必須采用對(duì)應(yīng)的地址,如AF_INET決定了要用ipv4地址(32位的)與端口號(hào)(16位的)的組合、AF_UNIX決定了要用一個(gè)絕對(duì)路徑名作為地址。
- type:指定socket類型。常用的socket類型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等。
- protocol:故名思意,就是指定協(xié)議。常用的協(xié)議有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它們分別對(duì)應(yīng)TCP傳輸協(xié)議、UDP傳輸協(xié)議、STCP傳輸協(xié)議、TIPC傳輸協(xié)議
當(dāng)我們調(diào)用socket創(chuàng)建一個(gè)socket時(shí),返回的socket描述字它存在于協(xié)議族(address family,AF_XXX)空間中,但沒(méi)有一個(gè)具體的地址。如果想要給它賦值一個(gè)地址,就必須調(diào)用bind()函數(shù),否則就當(dāng)調(diào)用connect()、listen()時(shí)系統(tǒng)會(huì)自動(dòng)隨機(jī)分配一個(gè)端口。
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen):(服務(wù)端)
正如上面所說(shuō)bind()函數(shù)把一個(gè)地址族中的特定地址賦給socket。例如對(duì)應(yīng)AF_INET、AF_INET6就是把一個(gè)ipv4或ipv6地址和端口號(hào)組合賦給socket。
- sockfd:即socket描述字,它是通過(guò)socket()函數(shù)創(chuàng)建了,唯一標(biāo)識(shí)一個(gè)socket。bind()函數(shù)就是將給這個(gè)描述字綁定一個(gè)名字。
- addr:一個(gè)const?struct?sockaddr *指針,指向要綁定給sockfd的協(xié)議地址。這個(gè)地址結(jié)構(gòu)根據(jù)地址創(chuàng)建socket時(shí)的地址協(xié)議族的不同而不同
- addrlen:對(duì)應(yīng)的是地址的長(zhǎng)度。
通常服務(wù)器在啟動(dòng)的時(shí)候都會(huì)綁定一個(gè)眾所周知的地址(如ip地址+端口號(hào)),用于提供服務(wù),客戶就可以通過(guò)它來(lái)接連服務(wù)器;而客戶端就不用指定,有系統(tǒng)自動(dòng)分配一個(gè)端口號(hào)和自身的ip地址組合。這就是為什么通常服務(wù)器端在listen之前會(huì)調(diào)用bind(),而客戶端就不會(huì)調(diào)用,而是在connect()時(shí)由系統(tǒng)隨機(jī)生成一個(gè)。
網(wǎng)絡(luò)字節(jié)序與主機(jī)字節(jié)序
主機(jī)字節(jié)序就是我們平常說(shuō)的大端和小端模式:不同的CPU有不同的字節(jié)序類型,這些字節(jié)序是指整數(shù)在內(nèi)存中保存的順序,這個(gè)叫做主機(jī)序。引用標(biāo)準(zhǔn)的Big-Endian和Little-Endian的定義如下:
a) Little-Endian就是低位字節(jié)排放在內(nèi)存的低地址端,高位字節(jié)排放在內(nèi)存的高地址端。
b) Big-Endian就是高位字節(jié)排放在內(nèi)存的低地址端,低位字節(jié)排放在內(nèi)存的高地址端。
網(wǎng)絡(luò)字節(jié)序:4個(gè)字節(jié)的32 bit值以下面的次序傳輸:首先是0~7bit,其次8~15bit,然后16~23bit,最后是24~31bit。這種傳輸次序稱作大端字節(jié)序。由于TCP/IP首部中所有的二進(jìn)制整數(shù)在網(wǎng)絡(luò)中傳輸時(shí)都要求以這種次序,因此它又稱作網(wǎng)絡(luò)字節(jié)序。字節(jié)序,顧名思義字節(jié)的順序,就是大于一個(gè)字節(jié)類型的數(shù)據(jù)在內(nèi)存中的存放順序,一個(gè)字節(jié)的數(shù)據(jù)沒(méi)有順序的問(wèn)題了。
所以:在將一個(gè)地址綁定到socket的時(shí)候,請(qǐng)先將主機(jī)字節(jié)序轉(zhuǎn)換成為網(wǎng)絡(luò)字節(jié)序,而不要假定主機(jī)字節(jié)序跟網(wǎng)絡(luò)字節(jié)序一樣使用的是Big-Endian。
int listen(int sockfd, int backlog):(服務(wù)端)
如果作為一個(gè)服務(wù)器,在調(diào)用socket()、bind()之后就會(huì)調(diào)用listen()來(lái)監(jiān)聽(tīng)這個(gè)socket,如果客戶端這時(shí)調(diào)用connect()發(fā)出連接請(qǐng)求,服務(wù)器端就會(huì)接收到這個(gè)請(qǐng)求。
listen函數(shù)的第一個(gè)參數(shù)即為要監(jiān)聽(tīng)的socket描述字,第二個(gè)參數(shù)為相應(yīng)socket可以排隊(duì)的最大連接個(gè)數(shù)。socket()函數(shù)創(chuàng)建的socket默認(rèn)是一個(gè)主動(dòng)類型的,listen函數(shù)將socket變?yōu)楸粍?dòng)類型的,等待客戶的連接請(qǐng)求。
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen):(服務(wù)端)
TCP服務(wù)器端依次調(diào)用socket()、bind()、listen()之后,就會(huì)監(jiān)聽(tīng)指定的socket地址了。TCP客戶端依次調(diào)用socket()、connect()之后就想TCP服務(wù)器發(fā)送了一個(gè)連接請(qǐng)求。TCP服務(wù)器監(jiān)聽(tīng)到這個(gè)請(qǐng)求之后,就會(huì)調(diào)用accept()函數(shù)取接收請(qǐng)求,這樣連接就建立好了。之后就可以開(kāi)始網(wǎng)絡(luò)I/O操作了,即類同于普通文件的讀寫I/O操作。
accept的第一個(gè)參數(shù)為服務(wù)器的socket描述字,是服務(wù)器開(kāi)始調(diào)用socket()函數(shù)生成的,稱為監(jiān)聽(tīng)socket描述字;而accept函數(shù)返回的是已連接的socket描述字。一個(gè)服務(wù)器通常通常僅僅只創(chuàng)建一個(gè)監(jiān)聽(tīng)socket描述字,它在該服務(wù)器的生命周期內(nèi)一直存在。內(nèi)核為每個(gè)由服務(wù)器進(jìn)程接受的客戶連接創(chuàng)建了一個(gè)已連接socket描述字,當(dāng)服務(wù)器完成了對(duì)某個(gè)客戶的服務(wù),相應(yīng)的已連接socket描述字就被關(guān)閉。
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen):(客戶端)
connect函數(shù)的第一個(gè)參數(shù)即為客戶端的socket描述字,第二參數(shù)為服務(wù)器的socket地址,第三個(gè)參數(shù)為socket地址的長(zhǎng)度。客戶端通過(guò)調(diào)用connect函數(shù)來(lái)建立與TCP服務(wù)器的連接。
?
萬(wàn)事具備只欠東風(fēng),至此服務(wù)器與客戶已經(jīng)建立好連接了。可以調(diào)用網(wǎng)絡(luò)I/O進(jìn)行讀寫操作了,即實(shí)現(xiàn)了網(wǎng)咯中不同進(jìn)程之間的通信!網(wǎng)絡(luò)I/O操作有下面幾組:
- read()/write()
- recv()/send()
- readv()/writev()
- recvmsg()/sendmsg()
- recvfrom()/sendto() ? (UDP)
C++ ?代碼 ? vs2013 ?(兩個(gè)cpp 分別用vs打開(kāi))
1 #include <stdio.h> 2 #include <winsock2.h> 3 #include<WS2tcpip.h> 4 #pragma comment(lib,"ws2_32.lib") 5 6 int main(int argc, char* argv[]) 7 { 8 //初始化WSA windows自帶的socket 9 WORD sockVersion = MAKEWORD(2, 2); 10 WSADATA wsaData; 11 if (WSAStartup(sockVersion, &wsaData) != 0) 12 { 13 return 0; 14 } 15 16 //創(chuàng)建服務(wù)端套接字 17 SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 18 if (slisten == INVALID_SOCKET) 19 { 20 printf("socket error !"); 21 return 0; 22 } 23 24 //服務(wù)端需要綁定ip和端口 25 sockaddr_in sin; 26 sin.sin_family = AF_INET; 27 sin.sin_port = htons(8888); 28 sin.sin_addr.S_un.S_addr = INADDR_ANY; //監(jiān)聽(tīng)任意的地址 29 if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR) //將服務(wù)端套接字與上面的ip和端口綁定 30 { 31 printf("bind error !"); 32 } 33 34 //開(kāi)始監(jiān)聽(tīng) 35 if (listen(slisten, 5) == SOCKET_ERROR) //用listen() 監(jiān)聽(tīng)前面綁定好的slisten套接字 36 { 37 printf("listen error !"); 38 return 0; 39 } 40 41 //循環(huán)接受數(shù)據(jù) 42 SOCKET sClient; //創(chuàng)建連接的套接字 43 sockaddr_in remoteAddr; 44 int nAddrlen = sizeof(remoteAddr); //用于接受客戶端地址 45 char revData[255]; //存儲(chǔ)接受的數(shù)據(jù) 46 while (1) 47 { 48 printf("等待連接...\n"); 49 sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen); //和客戶端 connect()對(duì)應(yīng) 50 if (sClient == INVALID_SOCKET) 51 { 52 printf("accept error !"); 53 continue; 54 } 55 char sendBuf[20] = { '\0' }; 56 printf("接受到一個(gè)連接:%s \r\n", inet_ntop(AF_INET, (void*)&remoteAddr.sin_addr, sendBuf, 16)); 57 58 //數(shù)據(jù)接收 59 int ret = recv(sClient, revData, 255, 0); 60 if (ret > 0) 61 { 62 revData[ret] = 0x00; 63 printf(revData); 64 } 65 66 //發(fā)送數(shù)據(jù)給客戶端 67 const char *sendData = "你好,TCP客戶端! \n"; 68 send(sClient, sendData, strlen(sendData), 0); 69 closesocket(sClient); //關(guān)閉已接通的套接字 70 } 71 72 73 closesocket(slisten); //關(guān)閉監(jiān)聽(tīng)的套接字 74 WSACleanup(); 75 return 0; 76 } Server_demo_TCP 1 #include<WINSOCK2.H> 2 #include<STDIO.H> 3 #include<iostream> 4 #include<cstring> 5 #include <string> 6 #include<WS2tcpip.h> 7 using namespace std; 8 #pragma comment(lib, "ws2_32.lib") 9 int main() 10 { 11 //初始化WSA windows自帶的socket 12 WORD sockVersion = MAKEWORD(2, 2); 13 WSADATA data; 14 if (WSAStartup(sockVersion, &data) != 0) 15 { 16 return 0; 17 } 18 19 //創(chuàng)建客戶端套接字 20 while (true) 21 { 22 SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //客戶端套接字 23 if (sclient == INVALID_SOCKET) 24 { 25 printf("invalid socket!"); 26 return 0; 27 } 28 29 sockaddr_in serAddr; 30 serAddr.sin_family = AF_INET; 31 serAddr.sin_port = htons(8888); 32 inet_pton(AF_INET, "127.0.0.1", (void*)&serAddr.sin_addr.S_un.S_addr); 33 if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR) //與指定IP地址和端口的服務(wù)端連接 34 { 35 printf("connect error !"); 36 closesocket(sclient); 37 return 0; 38 } 39 40 //string data; 41 //cin >> data; 42 //const char * sendData; 43 //sendData = data.c_str(); //string轉(zhuǎn)const char* 44 // char * sendData1 = "你好,TCP服務(wù)端,我是客戶端\n"; 45 //send(sclient, sendData1, strlen(sendData1), 0); 46 47 printf("輸入你想傳輸?shù)挠⑽?#xff1a; \n"); 48 string data; 49 cin >> data; 50 const char * sendData2; 51 sendData2 = data.c_str(); //string轉(zhuǎn)const char* 52 send(sclient, sendData2, strlen(sendData2), 0); 53 54 55 char recData[255]; 56 int ret = recv(sclient, recData, 255, 0); 57 if (ret>0){ 58 recData[ret] = 0x00; 59 printf(recData); 60 } 61 closesocket(sclient); 62 63 } 64 WSACleanup(); 65 return 0; 66 67 } Client_demo_TCP?
1 #include <stdio.h> 2 #include <winsock2.h> 3 #include<WS2tcpip.h> 4 #pragma comment(lib,"ws2_32.lib") 5 6 int main(int argc, char* argv[]) 7 { 8 WSADATA wsaData; 9 WORD sockVersion = MAKEWORD(2, 2); 10 if (WSAStartup(sockVersion, &wsaData) != 0) 11 { 12 return 0; 13 } 14 15 SOCKET serSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 16 if (serSocket == INVALID_SOCKET) 17 { 18 printf("socket error !"); 19 return 0; 20 } 21 22 sockaddr_in serAddr; 23 serAddr.sin_family = AF_INET; 24 serAddr.sin_port = htons(8888); 25 serAddr.sin_addr.S_un.S_addr = INADDR_ANY; 26 if (bind(serSocket, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR) 27 { 28 printf("bind error !"); 29 closesocket(serSocket); 30 return 0; 31 } 32 33 sockaddr_in remoteAddr; 34 int nAddrLen = sizeof(remoteAddr); 35 while (true) 36 { 37 char recvData[255]; 38 int ret = recvfrom(serSocket, recvData, 255, 0, (sockaddr*)&remoteAddr, &nAddrLen); 39 if (ret > 0) 40 { 41 recvData[ret] = 0x00; 42 char sendBuf[20] = { '\0' }; 43 printf("接受到一個(gè)連接:%s \r\n", inet_ntop(AF_INET, (void*)&remoteAddr.sin_addr, sendBuf, 16)); 44 printf(recvData); 45 } 46 47 const char * sendData = "一個(gè)來(lái)自服務(wù)端的UDP數(shù)據(jù)包\n"; 48 sendto(serSocket, sendData, strlen(sendData), 0, (sockaddr *)&remoteAddr, nAddrLen); 49 50 } 51 closesocket(serSocket); 52 WSACleanup(); 53 return 0; 54 } Server_demo_UDP 1 #include <stdio.h> 2 #include <winsock2.h> 3 #include<WS2tcpip.h> 4 #pragma comment(lib,"ws2_32.lib") 5 6 int main(int argc, char* argv[]) 7 { 8 WORD socketVersion = MAKEWORD(2, 2); 9 WSADATA wsaData; 10 if (WSAStartup(socketVersion, &wsaData) != 0) 11 { 12 return 0; 13 } 14 SOCKET sclient = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 15 16 sockaddr_in sin; 17 sin.sin_family = AF_INET; 18 sin.sin_port = htons(8888); 19 /*sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");*/ 20 inet_pton(AF_INET, "127.0.0.1", (void*)&sin.sin_addr.S_un.S_addr); 21 22 int len = sizeof(sin); 23 24 const char * sendData = "來(lái)自客戶端的數(shù)據(jù)包.\n"; 25 sendto(sclient, sendData, strlen(sendData), 0, (sockaddr *)&sin, len); 26 27 char recvData[255]; 28 int ret = recvfrom(sclient, recvData, 255, 0, (sockaddr *)&sin, &len); 29 if (ret > 0) 30 { 31 recvData[ret] = 0x00; 32 printf(recvData); 33 } 34 system("pause"); 35 closesocket(sclient); 36 WSACleanup(); 37 return 0; 38 } Client_demo_UDP?
主要參考:http://www.cnblogs.com/skynet/archive/2010/12/12/1903949.html
? ? ? ? ? ? ? ? ??http://blog.csdn.net/xiaoquantouer/article/details/58001960
如有侵權(quán),請(qǐng)告知~
?
轉(zhuǎn)載于:https://www.cnblogs.com/codebirdhan/p/7462889.html
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的Windows socket c++ TCP UDP 简单客户端 vs2013的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: zhm怎么取网名?
- 下一篇: java应用之solr入门篇