步骤如下:
服务器:
1.初始化
包含Winsock2.h头文件和引用ws2_32.lib静态库。 #include <WinSock2.h> #pragma comment(lib,"ws2_32.lib")
WSAStartUp函数
2.创建侦听套接字
socket
3.绑定ip和端口,绑定侦听套接字
SOCKADDR_IN
bind
4.开启监听
listen
5.等待客户端连接
accept
6.收发数据
recv/send
客户端:
1.初始化
包含Winsock2.h头文件和引用ws2_32.lib静态库。 #include <WinSock2.h> #pragma comment(lib,"ws2_32.lib")
WSAStartUp函数
2.创建连接套接字
socket
3.地址解析并连接服务器
SOCKADDR_IN
connect
4.收发数据
recv/send
-------------------------Code----------------------------------------
服务器代码如下:
#include "stdafx.h" #include <WinSock2.h> #include <WS2tcpip.h> #pragma comment(lib,"ws2_32.lib") #include <stdio.h>
int main() { /// 初始化socket WSADATA wsaData; WORD version = MAKEWORD(2,2); int result = 0; result = WSAStartup(version, &wsaData); if (0 != result) { std::cout << "WSAStartup() error." << std::endl; return -1; } /// 创建侦听socket SOCKET socketListen; socketListen = socket(AF_INET, SOCK_STREAM, 0); if (socketListen == INVALID_SOCKET) { WSACleanup(); std::cout << "socket() error." << std::endl; return -1; } /// 服务器地址结构 sockaddr_in svrAddress; svrAddress.sin_family = AF_INET; svrAddress.sin_addr.s_addr = INADDR_ANY; svrAddress.sin_port = htons(8000); /// 绑定服务器套接字 result = bind(socketListen, (sockaddr*)&svrAddress, sizeof(svrAddress)); if (result == SOCKET_ERROR) { closesocket(socketListen); WSACleanup(); std::cout << "bind() error." << std::endl; return -1; } /// 开启监听 result = listen(socketListen, 5); if (result == SOCKET_ERROR) { closesocket(socketListen); WSACleanup(); std::cout << "listen() error." << std::endl; return -1; } std::cout << "服务器启动成功,监听端口:" << ntohs(svrAddress.sin_port) << std::endl; /// select模型 fd_set allSockSet; FD_ZERO(&allSockSet); FD_SET(socketListen, &allSockSet); // 将socketListen加入套接字集合中 while (true) { fd_set readSet; FD_ZERO(&readSet); //初始化可读队列 readSet = allSockSet; result = select(0, &readSet, NULL, NULL, NULL); if (result == SOCKET_ERROR) { std::cout << "select() error." << std::endl; break; } if (FD_ISSET(socketListen, &readSet)) { sockaddr_in clientAddr; int len = sizeof(clientAddr); SOCKET clientSocket = accept(socketListen, (sockaddr*)&clientAddr, &len); if (clientSocket == INVALID_SOCKET) { std::cout << "accept() error." << std::endl; break; } FD_SET(clientSocket, &allSockSet); /// 将新创建的套接字加入到集合中 char ipAddress[16] = { 0 }; inet_ntop(AF_INET, &clientAddr, ipAddress, 16); std::cout << "有新的连接[" << ipAddress << ":" << ntohs(clientAddr.sin_port) << "], 目前客户端的数量为:" << allSockSet.fd_count - 1 << std::endl; //去掉一个侦听套接字 continue; }
for (u_int i = 0; i < allSockSet.fd_count; ++i) { SOCKET socket = allSockSet.fd_array[i]; sockaddr_in clientAddr; int len = sizeof(clientAddr); getpeername(socket, (struct sockaddr *)&clientAddr, &len); //获得与套接口相连的远程协议地址 char ipAddress[16] = { 0 }; inet_ntop(AF_INET, &clientAddr, ipAddress, 16); /// 可读性监视,可读性指有连接到来、有数据到来、连接已关闭、重置或终止 if (FD_ISSET(socket, &readSet)) { char bufRecv[100]; result = recv(socket, bufRecv, 100, 0); if (result == SOCKET_ERROR) { DWORD err = WSAGetLastError(); if (err == WSAECONNRESET) /// 客户端的socket没有被正常关闭,即没有调用closesocket { std::cout << "客户端[" << ipAddress << ":" << ntohs(clientAddr.sin_port) << "]被强行关闭, "; } else { std::cout << "recv() error," << std::endl; } closesocket(socket); FD_CLR(socket, &allSockSet); std::cout << "目前客户端的数量为:" << allSockSet.fd_count - 1 << std::endl; break; } else if (result == 0) /// 客户端的socket调用closesocket正常关闭 { closesocket(socket); FD_CLR(socket, &allSockSet); std::cout << "客户端[" << ipAddress << ":" << ntohs(clientAddr.sin_port) << "]已经退出,目前客户端的数量为:" << allSockSet.fd_count - 1 << std::endl; break; } bufRecv[result] = '\0'; std::cout << "来自客户端[" << ipAddress << ":" << ntohs(clientAddr.sin_port) << "]的消息:" << bufRecv << std::endl; char szSend[256] = "朕已经收到,你可以滚了!"; send(socket, szSend, strlen(szSend), 0); } } } for (u_int i = 0; i < allSockSet.fd_count; ++i) { SOCKET socket = allSockSet.fd_array[i]; closesocket(socket); } WSACleanup(); return 0; }
客户端代码:
#include "stdafx.h" #include <iostream> #include <WS2tcpip.h> #include <WinSock2.H> using namespace std; #pragma comment(lib, "ws2_32.lib")
#define SERVER_ADDRESS "192.168.1.179" #define SERVER_PORT 8000
#define SOCKET_NUM 120 /// 客户端socket的个数,修改该值可以改变连接到服务器的客户端个数
SOCKET socketClient;
char g_szBuf[512] = "";
HANDLE hMutex;
void Input();
void Recv();
DWORD WINAPI ThreadProc( _In_ LPVOID lpParameter );
DWORD WINAPI SendDataThreadProc( _In_ LPVOID lpParameter );
int main() { WORD wVersionRequested = MAKEWORD(2, 2); WSADATA wsaData; int err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) return 1;
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { WSACleanup(); std::cout << "WSAStartup() error." << std::endl; return -1; }
socketClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (socketClient == INVALID_SOCKET) { WSACleanup(); std::cout << "socket() error." << std::endl; return -1; }
SOCKADDR_IN server; memset(&server, 0, sizeof(SOCKADDR_IN)); server.sin_family = AF_INET; server.sin_port = htons(SERVER_PORT); inet_pton(server.sin_family, SERVER_ADDRESS, &server.sin_addr);
err = connect(socketClient, (struct sockaddr *)&server, sizeof(SOCKADDR_IN)); if (err == SOCKET_ERROR) { std::cout << "connect() error." << std::endl; closesocket(socketClient); WSACleanup(); return -1; }
hMutex = CreateMutex(NULL, false, (LPCWSTR)"MutexOne"); if (NULL == hMutex) { printf("创建互斥对象失败!\n"); return -1; }
DWORD dwThreadId = 0;
/*HANDLE hThread = CreateThread(NULL, NULL, &SendDataThreadProc, NULL, 0, &dwThreadId); if (NULL == hThread) { printf("创建发送线程失败!\n"); return -1; }*/
HANDLE hThread2 = CreateThread(NULL, NULL, &ThreadProc, NULL, 0, &dwThreadId); if (NULL == hThread2) { printf("创建接收线程失败!\n"); return -1; }
Input(); // Recv(); closesocket(socketClient); WSACleanup();
return 0; }
void Input() { while (true) { WaitForSingleObject(hMutex, INFINITE); char szInput[256] = ""; printf("Me:"); scanf("%s", szInput); if (strcmp(szInput, "exit") == 0) { break; } else { send(socketClient, szInput, strlen(szInput), 0); } // printf("\n"); ReleaseMutex(hMutex); } }
void Recv() { while (true) { recv(socketClient, g_szBuf, sizeof(g_szBuf), 0); printf("Me Recv Form Server:%s\n", g_szBuf);
} }
DWORD WINAPI ThreadProc(_In_ LPVOID lpParameter) { while (true) { WaitForSingleObject(hMutex, INFINITE); recv(socketClient, g_szBuf, sizeof(g_szBuf), 0); printf("Recv Form Server:%s\n\n", g_szBuf); ReleaseMutex(hMutex); }
return 0; }
DWORD WINAPI SendDataThreadProc(_In_ LPVOID lpParameter) { while (true) { WaitForSingleObject(hMutex, INFINITE); char szInput[256] = ""; printf("Me:"); scanf("%s", szInput); if (strcmp(szInput, "exit") == 0) { break; } else { send(socketClient, szInput, strlen(szInput), 0); } printf("\n"); ReleaseMutex(hMutex); }
return 0; }