Sockets_server.cpp
初始化套结字动态库WSAStartup()->创建套接字socket()->绑定套接字bind()->监听(listen())->接受客户端请求accept()->接收客户端数据recv()->关闭套接字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 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; }