多线程的服务端
//Server
#pragma comment(lib, "ws2_32.lib")
#include <WinSock2.h>
#include <iostream>
#include<process.h>
using namespace std;
//处理服务
unsigned _stdcall do_service(void* p)
{
int conn = (SOCKET)p;
char buf[1024] = { 0 };
while (1)
{
//接收
int ret = recv(conn, buf, sizeof(buf), 0);
if (ret == SOCKET_ERROR)
{
cout << "error with code = " << WSAGetLastError() << endl;
exit(1);
}
if (ret == 0)
{
cout << "client close" << endl;
break;
}
if (ret > 0)
{
cout << buf << endl;
send(conn, buf, strlen(buf), 0); //回射回去
}
memset(buf, 0, sizeof buf); //置0
}
closesocket(conn);
return 0;
}
int main(void)
{
WORD wVersionRequested; //两个字节,指定使用的版本号
WSADATA wsaData; //WSADATA 结构存储 Windows 套接字调用返回的初始化信息对
int err;
//makeword(a,b)是将两个byte型合并成一个word型,一个在高8位(b),一个在低8位(a)
wVersionRequested = MAKEWORD(2, 2); //指定版本号
err = WSAStartup(wVersionRequested, &wsaData); //启动Windows Socket
if (err != 0) {
return 1;
}
//检查协议栈的安装信息
if (LOBYTE(wsaData.wVersion) != 2 ||
HIBYTE(wsaData.wVersion) != 2) {
WSACleanup();
return 1;
}
//或者使用下面的方法
//if (wsaData.wVersion != wVersionRequested)
//{
// //Winsock版本不匹配
// WSACleanup();
// return 1;
//}
SOCKET listenfd; //创建socket
listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); //TCP协议
if (listenfd == INVALID_SOCKET) //创建失败
{
cout << "error with code = " << WSAGetLastError() << endl; //WSAGetLastError()获取错误码
exit(1);
}
sockaddr_in servaddr; //服务器地址
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET; //地址族
//servaddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //指定IP地址 4字节主机字节序转换为网络字节序
servaddr.sin_port = htons(8888); //端口号 2字节主机字节序转换为网络字节序
int ret;
int opt = 1;
ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)); //设置地址重复利用
if (ret == SOCKET_ERROR)
{
cout << "error with code = " << WSAGetLastError() << endl;
exit(1);
}
//绑定
ret = bind(listenfd, (sockaddr*)&servaddr, sizeof(servaddr));
if (ret == SOCKET_ERROR)
{
cout << "error with code = " << WSAGetLastError() << endl;
exit(1);
}
//监听
ret = listen(listenfd, SOMAXCONN);
if (ret == SOCKET_ERROR)
{
cout << "error with code = " << WSAGetLastError() << endl;
exit(1);
}
SOCKET conn;
sockaddr_in peeraddr;
int peerlen;
while (1)
{
peerlen = sizeof(peeraddr);
conn = accept(listenfd, (sockaddr*)&peeraddr, &peerlen);
if (conn == INVALID_SOCKET)
{
cout << "error with code = " << WSAGetLastError() << endl;
exit(1);
}
//将一个十进制网络字节序转换为点分十进制IP格式的字符串 2字节网络字节序转换为主机字节序
cout << inet_ntoa(peeraddr.sin_addr) << " " << ntohs(peeraddr.sin_port) << endl;
unsigned threadId;
HANDLE hThread=(HANDLE)_beginthreadex(NULL, 0, do_service, (void*)conn, 0, &threadId);
if (hThread == NULL)
{
cout << "error with code=" << GetLastError() << endl;
}
CloseHandle(hThread);
}
WSACleanup();
return 0;
}
注意在服务端没有调用WaitForSignalObject,否则主线程会阻塞,其他客户端不能通信。