在Windows平臺上主要有兩個版本的Socket Api函數:
WinSock 1.1和WinSock 2.2 , 2.2版本默認兼容1.1版本,
1.1 winsock.h wsock32.lib winsock.dll
2.2 winsock2.h ws2 32.lib ws2 32.dllios
2.0版本的Socket比1.1的多一些高級的功能如:
多重協議支持:經過SPI接口支持其餘協議;
多重命名空間:根據服務與主機名選擇協議
重疊10模式:加強10吞吐量與提升性能
分散與聚合:從多個緩衝區發送與接收數據
有條件接受:有選擇性地決定是否接受鏈接;
套接字共享:多個進程共享一個套接字句柄。編程
Socket套接字類型:
比較經常使用的包括:流式套接字(使用TCP) ,數據報套接字(使用UDP) ,原始套接字等
TCP與UDP各有優缺點:
TCP :面向鏈接、穩定、須要資源多;
UDP :面向無鏈接(通常狀況下)、不穩定、須要資源少。
用手機打電話時面向鏈接的,用手機發短信是面向無鏈接的,目前來講網絡上比較經常使用的是TCP類型的衰接字。安全
TCP與UDP的區別:
1.基於鏈接與無鏈接
2.對系統資源的要求(TCP較多,UDP少)
3.UDP程序結構較簡單
4.流模式(TCP)與數據報模式(UDP)
TCP保證數據正確性, UDP可能丟包
TCP保證數據順序, UDP不保證服務器
具體編程時的區別
1. socket0的參數不一樣
2. UDP Server不須要淘用listen和accept
3. UDP收發數據用sendto/recvfrom函數
4. TCP:地址信息在connect/accept時肯定
UDP :在sendto/recvfrom函數中每次均需指定地址信息
5. UDP : shutdown函數無效網絡
部分知足如下幾點要求時,應該採用UDP面向數據報方式
1.網絡數據大多爲短消息
2.擁有大量Client
3.對數據安全性無特殊要求
4.網絡負擔很是重,但對響應速度要求高socket
TCP類型Socket程序開發流程:
TCP服務端: WSASartup, socket, bind, listen, accept, read, write, closesocket, WSACleanup.
TCP客戶端: WSASartup, socket, connect, read, write, closesocket, WSACleanup.函數
流程圖:性能
這種結構雖然能不停地接收客戶端新的鏈接,但不能處理複雜的業務。spa
服務器端:code
#include<WinSock2.h> #include<Windows.h> #include<stdio.h> #include<iostream> #pragma comment(lib,"ws2_32.lib") int main() { WORD ver = MAKEWORD(2, 2); WSADATA dat; //WinSocket啓動 WSAStartup(ver, &dat); //創建一個socket SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //AF_INET建立一個IPV4的套接字,SOCK_STREAM面向數據流的,IPPROTO_TCP TCP if (INVALID_SOCKET == _sock) { printf("ERROR:創建失敗!\n"); } //1.綁定 sockaddr_in _sin = {}; //建立網絡地址 _sin.sin_family = AF_INET; _sin.sin_port = htons(4567); //Host to Network Short _sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // IP地址 if (bind(_sock, (sockaddr *)&_sin, sizeof(_sin)) == SOCKET_ERROR) { printf("ERROR:綁定失敗!\n"); } else { printf("TRUE:綁定成功!\n"); } //2.監聽網絡端口 if (listen(_sock, 5) == SOCKET_ERROR)//第二個參數爲最大等待多少人能夠同時鏈接 { printf("ERROR:監聽失敗!\n"); } else { printf("TRUE:監聽成功!\n"); } //3.等待接收客戶端鏈接 sockaddr_in clientAddr = {}; int nAddrLen = sizeof(sockaddr_in); SOCKET _cSOCK = INVALID_SOCKET; char msgBuff[] = "Hello,My is Server!\n"; while (1) { _cSOCK = accept(_sock, (sockaddr *)&clientAddr, &nAddrLen); if (_cSOCK == INVALID_SOCKET) { printf("ERROR:無效客戶端SOCKET!\n"); } printf("新客戶端加入:IP = %s\n", inet_ntoa(clientAddr.sin_addr));//inet_ntoa(clientAddr.sin_addr)將接收到的IP地址轉化爲字符串 //向客戶端發送一條數據 send(_cSOCK, msgBuff, strlen(msgBuff) + 1, 0); } //5,關閉自身的socket closesocket(_sock); //WinSocket關閉 WSACleanup(); system("pause"); return 0; }
客戶端:
#include<WinSock2.h> #include<Windows.h> #include<stdio.h> #pragma comment(lib,"ws2_32.lib") int main() { WORD ver = MAKEWORD(2, 2); WSADATA dat; WSAStartup(ver, &dat); //創建一個socket SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (INVALID_SOCKET == _sock) { printf("ERROR:創建失敗!\n"); } //鏈接服務器 sockaddr_in _sin = {}; //建立網絡地址 _sin.sin_family = AF_INET; _sin.sin_port = htons(4567); //Host to Network Short _sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//inet_addr("127.0.0.1"); // IP地址 int ret = connect(_sock, (sockaddr *)&_sin, sizeof(sockaddr_in)); if (SOCKET_ERROR == ret) { printf("ERROR:鏈接失敗!\n"); } else { printf("鏈接成功!\n"); } //接收服務器信息 char recvBuff[256] = {}; int nlen = recv(_sock, recvBuff, 256, 0); if (nlen <= 0) { printf("ERROR:接收失敗!\n"); } else { printf("接收到數據:%s\n", recvBuff); } //關閉套接字 closesocket(_sock); //WinSocket啓動 WSAStartup(ver, &dat); //WinSocket關閉 WSACleanup(); getchar(); return 0; }