步骤如下:
服务器:
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;
}