多并发服务器实验
目录
实验设备:
目标系统:Windows
软件工具:vs2022/vc6/dev
实验要求:
- 用select完成使用IO复用模型的TCP并发服务器设计;
- 用多线程完成TCP并发服务器设计。
实验内容:
大致思路:
- 通讯建立后首先由服务器端发送消息,客户端接收消息;接着客户端发送消息,服务器端接收消息,实现交互发送消息。
- 服务器同时可以和 多个客户端建立连接,进行交互;用建立连接时服务器端接收的客户端套接字来唯一标识该客户端。服务器端可以随时接收客户端的连接并与其进行交互。
- 在某次交互中,服务器端或某客户端有一方发送"end"即终止服务器与其的通信;服务器还可以继续接收其他客户端的请求,与其他客户端通信。
服务器端:
- 初始化winsock2.DLL
2、创建套接字
3、绑定端口和IP
4、将套接字设为监听状态
5、主线程循环接收客户端的连接
6、线程通讯部分
1)、与客户端通讯,先发送再接收数据
2)、接收客户端数据
客户端:
1、初始化winsock2.DLL
2、创建套接字
3、连接服务器
4、实现交互部分,客户端先接收后发送数据
1)、接收服务端消息
2)、发送信息给服务器
结果截图:
完整源代码:
服务器端代码:
#include <WinSock2.h>
#include <ws2tcpip.h>
#include <iostream>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
#include<windows.h>
#define PORT 65432
DWORD WINAPI ThreadFun(LPVOID lpThreadParameter);
int main()
{
//初始化winsock2.DLL
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
if (WSAStartup(wVersionRequested, &wsaData) != 0)
{
cout << "加载winsock.dll失败!" << endl;
return 0;
}
//创建套接字
SOCKET sock_server;
if ((sock_server = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
{
cout << "创建套接字失败!错误代码:" << WSAGetLastError() << endl;
WSACleanup();
return 0;
}
//绑定端口和Ip
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);//绑定本机的环回地址
if (SOCKET_ERROR == bind(sock_server, (SOCKADDR*)&addr, sizeof(sockaddr_in)))
{
cout << "地址绑定失败!错误代码:" << WSAGetLastError() << endl;
closesocket(sock_server);
WSACleanup();
return 0;
}
//将套接字设为监听状态
listen(sock_server, 0);
//主线程循环接收客户端的连接
while (1)
{
sockaddr_in addrClient;
int len = sizeof(sockaddr_in);
//接收成功返回与client通讯的socket
SOCKET con = accept(sock_server, (SOCKADDR*)&addrClient, &len);
if (con != INVALID_SOCKET)
{
//创建线程 并且传入与client通讯的套接字
HANDLE hThread = CreateThread(NULL, 0, ThreadFun, (LPVOID)con, 0, NULL);
CloseHandle(hThread); //关闭对线程的引用
}
}
closesocket(sock_server);
WSACleanup();
return 0;
}
//线程通讯部分
DWORD WINAPI ThreadFun(LPVOID lpThreadParameter)
{
//与客户端通讯 先发送再接收数据
SOCKET sock = (SOCKET)lpThreadParameter;
cout << "成功和" << sock << "建立连接!" << endl;
while (1)
{
char msgbuffer[1000];//字符缓冲区
printf("服务器向%d发送信息:\n", sock);
cin.getline(msgbuffer, sizeof(msgbuffer));
int size = send(sock, msgbuffer, sizeof(msgbuffer), 0);//给客户端发送一段信息
if (strcmp(msgbuffer, "end\0") == 0)
{
cout << "关闭和" << sock << "的连接!" << endl;
return 0;
}
if (size == SOCKET_ERROR || size == 0)
{
cout << "发送信息失败!错误代码:" << WSAGetLastError() << endl;
return 0;
}
else cout << "信息发送成功!" << endl;
//接收客户端数据
msgbuffer[999] = { 0 };
int ret = recv(sock, msgbuffer, sizeof(msgbuffer), 0);
if (ret == SOCKET_ERROR || ret == 0)
{
cout << sock << "断开了连接!" << endl;
break;
}
else cout << sock << " 发来的信息: " << msgbuffer << endl;
}
return 0;
}
客户端代码:
#include <winsock2.h>
#include <WS2tcpip.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "ws2_32.lib")
#define PORT 65432
int main()
{
//初始化winsock2.DLL
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
if (WSAStartup(wVersionRequested, &wsaData) != 0)
{
cout << "加载winsock.dll失败!" << endl;
return 0;
}
//创建套接字
SOCKET sock_client;
if ((sock_client = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
{
cout << "创建套接字失败!错误代码:" << WSAGetLastError() << endl;
WSACleanup();
return 0;
}
//连接服务器
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);//绑定本机的环回地址
int len = sizeof(sockaddr_in);
if (connect(sock_client, (SOCKADDR*)&addr, len) == SOCKET_ERROR) {
cout << "连接失败!错误代码:" << WSAGetLastError() << endl;
return 0;
}
//实现交互部分,客户端先接收后发送数据
while (1)
{
//接收服务端的消息
char msgbuffer[1000] = { 0 };
int size = recv(sock_client, msgbuffer, sizeof(msgbuffer), 0);
if (strcmp(msgbuffer, "end\0") == 0)
{
cout << "服务器端已经关闭连接!" << endl;
break;
}
if (size < 0)
{
cout << "接收信息失败!错误代码:" << WSAGetLastError() << endl;
break;
}
else if (size == 0)
{
cout << "对方已经关闭连接" << endl;
break;
}
else cout << "服务器发来消息:" << msgbuffer << endl;
//从键盘输入一行文字发送给服务器
msgbuffer[999] = 0;
cout << "给服务器发送信息:" << endl;
cin.getline(msgbuffer, sizeof(msgbuffer));
if (strcmp(msgbuffer, "end\0") == 0)
{
cout << "关闭连接!" << endl;
break;
}
int ret = send(sock_client, msgbuffer, sizeof(msgbuffer), 0);
if (ret == SOCKET_ERROR || ret == 0)
{
cout << "发送信息失败!错误代码:" << WSAGetLastError() << endl;
break;
}
else cout << "信息发送成功!" << endl;
}
closesocket(sock_client);
WSACleanup();
return 0;
}