Sockets_server.cpp
編程
初始化套結字動態庫WSAStartup()->建立套接字socket()->綁定套接字bind()->監聽(listen())->接受客戶端請求accept()->接收客戶端數據recv()->關閉套接字closesocket()->釋放套接字資源WSACleanup()windows
#include "stdafx.h" #define BUF_SIZE 64 #include "winsock2.h" #pragma comment(lib, "ws2_32.lib") int _tmain(int argc, _TCHAR* argv[]) { WSADATA wsd; //存放windows socket初始化信息 SOCKET sServer; //服務端套接字 SOCKET sClient; //客戶端套接字 SOCKADDR_IN addrServ; //服務器地址 char buf[BUF_SIZE]; //接收數據緩衝區 int retVal; /* #define MAKEWORD(a,b) ((WORD) (((BYTE) (a)) | ((WORD) ((BYTE) (b))) << 8)) makeword是將兩個byte型合併成一個word型,一個在高8位(b),一個在低8位(a)。 在WSAStartup裏面,MAKEWORD(2, 2)指Windows Sockets版本號,高位字節指出副版本(修正)號,低位字節指明主版本號。 */ //初始化套接字動態庫 if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) { printf("WSAStartup failed!\n"); return 1; } /* AF 表示ADDRESS FAMILY 地址族,PF 表示PROTOCOL FAMILY 協議族, 但這兩個宏定義是同樣的,因此使用哪一個都沒有關係。 Winsock2.h中#define AF_INET 2,#define PF_INET AF_INET, 因此在windows中AF_INET與PF_INET徹底同樣。而在Unix/Linux系統中, 在不一樣的版本中這二者有微小差異。對於BSD,是AF,對於POSIX是PF。 UNIX系統支持AF_INET,AF_UNIX,AF_NS等,而DOS, Windows中僅支持AF_INET,它是網際網區域。 PF_INET, AF_INET: Ipv4網絡協議; PF_INET6, AF_INET6: Ipv6網絡協議。 */ /* IPPROTO_TCP:指使用tcp協議, #define IPPROTO_TCP 6 // tcp。 */ /* SOCK_STREAM:提供面向鏈接的穩定數據傳輸,即TCP協議。 */ //建立套接字 // 第一個參數,指定地址簇(TCP/IP只能是AF_INET,也可寫成PF_INET) // 第二個,選擇套接字的類型(流式套接字) // 第三個,特定地址家族相關協議(0爲自動) sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (INVALID_SOCKET == sServer) { printf("socket failed!\n"); WSACleanup();//釋放套接字資源 return -1; } /* htons在Windows和Linux網絡編程時須要用到的,用來將主機字節順序轉化爲網絡字節順序, 功能是將一個無符號短整型的主機數值轉換爲網絡字節順序,即大尾順序(big-endian),即高位字節存放在內存的低地址處。 網絡字節順序是TCP/IP中規定好的一種數據表示格式,它與具體的CPU類型、操做系統等無關,從而能夠保證數據在不一樣主機之間傳輸時可以被正確解釋,網絡字節順序採用big-endian排序方式。 咱們經常使用的 x86 CPU (intel, AMD) 電腦是 little-endian,也就是整數的低位字節放在內存的低字節處。 而little-endian指,地址的低位存儲值的低位。 */ //設置服務器套接字地址 addrServ.sin_family = AF_INET; addrServ.sin_port = htons(4999); addrServ.sin_addr.s_addr = INADDR_ANY; // 套接字sockSrv與本地地址相連 // int bind(SOCKET s, const struct sockaddr* name, int namelen); // 第一個參數,指定須要綁定的套接字; // 第二個參數,指定該套接字的本地地址信息,該地址結構會隨所用的網絡協議的不一樣而不一樣 // 第三個參數,指定該網絡協議地址的長度 // PS: struct sockaddr{ u_short sa_family; char sa_data[14];}; // sa_family指定該地址家族, sa_data起到佔位佔用一塊內存分配區的做用 // 在TCP/IP中,可以使用sockaddr_in結構替換sockaddr,以方便填寫地址信息 // // struct sockaddr_in{ short sin_family; unsigned short sin_port; struct in_addr si n_addr; char sin_zero[8];}; // sin_family表示地址族,對於IP地址,sin_family成員將一直是AF_INET。 // sin_port指定將要分配給套接字的端口。 // sin_addr給出套接字的主機IP地址。 // sin_zero[8]給出填充數,讓sockaddr_in與sockaddr結構的長度同樣。 // 將IP地址指定爲INADDR_ANY,容許套接字向任何分配給本地機器的IP地址發送或接收數據。 // 若是想只讓套接字使用多個IP中的一個地址,可指定實際地址,用inet_addr()函數。 retVal = bind(sServer, (LPSOCKADDR)&addrServ, sizeof(SOCKADDR_IN)); if (SOCKET_ERROR == retVal) { printf("bind failed!\n"); closesocket(sServer);//關閉套接字 WSACleanup(); return -1; } // 將套接字設置爲監聽模式(鏈接請求), listen()通知TCP服務器準備好接收鏈接 // int listen(SOCKET s, int backlog); // 第一個參數指定須要設置的套接字,第二個參數爲(等待鏈接隊列的最大長度) retVal = listen(sServer, 1); if (SOCKET_ERROR == retVal) { printf("listen failed!\n"); closesocket(sServer); WSACleanup(); return -1; } //接受客戶端請求 sockaddr_in addrClient; int addrClientlen = sizeof(addrClient); // 接收鏈接,等待客戶端鏈接 // SOCKET accept( SOCKET s, struct sockaddr* addr, int* addrlen); // 第一個參數,接收一個處於監聽狀態下的套接字 // 第二個參數,sockaddr用於保存客戶端地址的信息 // 第三個參數,用於指定這個地址的長度 // 返回的是向與這個監聽狀態下的套接字通訊的套接字 sClient = accept(sServer, (sockaddr FAR*)&addrClient, &addrClientlen); if (INVALID_SOCKET == sClient) { printf("accept failed!\n"); closesocket(sServer); WSACleanup(); return -1; } //接收客戶端數據 ZeroMemory(buf, BUF_SIZE); retVal = recv(sClient, buf, BUF_SIZE, 0); if (SOCKET_ERROR == retVal) { printf("recv failed!\n"); closesocket(sServer); closesocket(sClient); WSACleanup(); return -1; } printf("%s\n", buf); //關閉套接字 closesocket(sServer); closesocket(sClient); //釋放套接字資源 WSACleanup(); return 0; }
Sockets_Client.cpp服務器
初始化套結字動態庫WSAStartup()->建立套接字socket()->鏈接服務器connect()->向服務器發送數據send()->關閉套接字closesocket()->釋放套接字資源WSACleanup()網絡
#include "stdafx.h" #define BUF_SIZE 64 #include "winsock2.h" #pragma comment(lib, "ws2_32.lib") int _tmain(int argc, _TCHAR* argv[]) { WSADATA wsd; //存放windows socket初始化信息 SOCKET sHost; //服務器套接字 SOCKADDR_IN servAddr; //服務器地址 char buf[BUF_SIZE]; //接收數據緩衝區 int retVal; //初始化套結字動態庫 if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) { printf("WSAStartup failed!\n"); return -1; } //建立服務器套接字 sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (INVALID_SOCKET == sHost) { printf("socket failed!\n"); WSACleanup(); return -1; } //設置服務器地址 servAddr.sin_family = AF_INET; servAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); servAddr.sin_port = htons((short)4999); int nServAddlen = sizeof(servAddr); //鏈接服務器 retVal = connect(sHost, (LPSOCKADDR)&servAddr, sizeof(servAddr)); if (SOCKET_ERROR == retVal) { printf("connect failed!\n"); closesocket(sHost); WSACleanup(); return -1; } ZeroMemory(buf, BUF_SIZE); strcpy_s(buf, "MyTCP"); //向服務器發送數據 // 第一個參數,須要發送信息的套接字, // 第二個參數,包含了須要被傳送的數據, // 第三個參數是buffer的數據長度, // 第四個參數,一些傳送參數的設置 retVal = send(sHost, buf, strlen(buf), 0); if (SOCKET_ERROR == retVal) { printf("send failed!\n"); closesocket(sHost); WSACleanup(); return -1; } //關閉套接字和釋放資源 closesocket(sHost); WSACleanup(); return 0; }