服务器
- 流程
-
初始化WinSock
-
创建套接字serverSocket
-
设置服务器地址及端口信息
-
绑定地址到serverSocket
-
监听并设置客户端连接个数
-
while true
接收连接并返回一个套接字clients[i]注意:clients是一个SOCKET数组,对应请求连接的客户端
创建线程,返回一个句柄,将线程函数名作起始地址传递,并将i作下标传递 关闭句柄
-
WSACleanup以及套接字关闭处理
-
线程函数:接收clients[i]传递的消息并转发给已连接的客户实现聊天室功能
- 代码
#include <WinSock2.h>
#include <iostream>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
#define IP_ADDRESS "127.0.0.1" //本地地址
#define PORT 5555
const int LEN = 10; //最大连接客户数
SOCKET clientScoket[LEN]; //客户i对应的SOCKET
int curMax = 0; //已经连接的客户个数,不超过LEN
const int BufSize = 2000;
//创建线程
DWORD WINAPI ClientThread(LPVOID ipParameter)
{
int ind=(int)ipParameter;
int RET = 0;
char RecvBuffer[BufSize];
while (true) {
//Init RecvBuffer
memset(RecvBuffer, 0, sizeof(RecvBuffer));
RET = recv(clientScoket[ind], RecvBuffer, BufSize, 0);
if (RET == 0 || RET == SOCKET_ERROR){
cout << "-----------------------------------------------------------------------\n";
cout << ind << "号离开 \n";
cout << "-----------------------------------------------------------------------\n";
break;
}
cout << ind << ":" << RecvBuffer << endl;
// transmit
char SendBuffer[BufSize];
SendBuffer[0] = ind + '0';
SendBuffer[1] = ':';
int i = 0;
for (; i < strlen(RecvBuffer); ++i) SendBuffer[i + 2] = RecvBuffer[i];
SendBuffer[i + 2] = '\0';
for (i = 0; i < curMax; ++i) {
if (i != ind) {
int ret = send(clientScoket[i], SendBuffer, (int)strlen(SendBuffer), 0);
if (ret == SOCKET_ERROR) {
cout << "send to error" << endl;
break; //maybe break can't solve this problem.
}
}
}
}
return 0;
}
int main()
{
WSADATA wsa;
SOCKET severSocket;
struct sockaddr_in localAddr, clientAddr;
HANDLE h = NULL;
int RET;
//Init WinSock
if ( WSAStartup(MAKEWORD(2, 2), &wsa) != 0){
cout << "WSAStartup's init failed! \n";
return -1;
}
//Create SOCKET:TCP(AF_INET SOCK_STREAM)
severSocket = socket(AF_INET, SOCK_STREAM, 0);
if (severSocket == INVALID_SOCKET) {
cout << "socket failed" << GetLastError() << endl;
return -1;
}
//Set server's address
memset(&localAddr, 0, sizeof(localAddr));
localAddr.sin_family = AF_INET;
localAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS);
localAddr.sin_port = htons(PORT);
//bind socket
RET = bind(severSocket, (struct sockaddr*)&localAddr, sizeof(localAddr));
if (RET != 0){
cout << "bind failed \n";
return -1;
}
//listen LEN
RET = listen(severSocket, LEN);
if (RET != 0){
cout << "listen failed \n";
return -1;
}
cout << "---------------------------- Server starts ----------------------------\n";
int index=0;//index th client
while (true){
// accept
int addrLen = sizeof(clientAddr);
clientScoket[index] = accept(severSocket, (struct sockaddr*)&clientAddr, &addrLen);
if (clientScoket[index] == INVALID_SOCKET){
cout << "accept failed \n";
break;
}
// client information
cout << "-----------------------------------------------------------------------\n";
cout << "Client:" << index << " connect \n"
<< "Address:" << inet_ntoa(clientAddr.sin_addr) << " & Port:" << clientAddr.sin_port << endl;
cout << "-----------------------------------------------------------------------\n";
// assgin the task to Thread with SOCKET clientSocket[index]
h = CreateThread(NULL, 0, ClientThread, (LPVOID)index, 0, NULL);
++index;
++curMax;
if (h == NULL) {
cout << "Create thread failed \n";
break;
}
CloseHandle(h);
}
closesocket(severSocket);
for (int i(0); i < index;++i)
closesocket(clientScoket[i]);
WSACleanup();
return 0;
}
客户端
- 流程
- 初始化WinSock
- 创建套接字clientSocket
- 设置服务器地址及端口信息
- 连接
- 创建线程函数接收消息
- while true
发送当前用户输入的消息 - WSACleanup以及套接字关闭处理
- 线程函数:接收服务器转发的消息
- 代码
#include <WinSock2.h>
#include <iostream>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
#define PORT 5555
#define IP_ADDRESS "127.0.0.1"
const int BufSize = 2000;
DWORD WINAPI ServerThread(LPVOID ipParameter)
{
SOCKET clientSocket = (SOCKET)ipParameter;
int RET = 0;
char RecvBuffer[BufSize];
//初始化 recvBuffer
while (true) {
memset(RecvBuffer, 0, sizeof(RecvBuffer));
RET = recv(clientSocket, RecvBuffer, BufSize, 0);
if (RET == 0 || RET == SOCKET_ERROR){
cout << "error" << endl;
break;
}
cout << RecvBuffer << endl;
}
return 0;
}
int main()
{
WSADATA wsa;
SOCKET clientScoket;
struct sockaddr_in serveAddr;
HANDLE h = NULL;
int RET = 0;
char SendBuffer[BufSize];
// Init WinSock
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0){
cout << "Init WinSock failed" << endl;
return -1;
}
// creat socket
clientScoket = socket(AF_INET, SOCK_STREAM, 0);
if (clientScoket == INVALID_SOCKET){
cout << "socket failed" << GetLastError() << endl;
return -1;
}
// set server's address
memset(&serveAddr, 0, sizeof(serveAddr));
serveAddr.sin_family = AF_INET;
serveAddr.sin_addr.s_addr = inet_addr(IP_ADDRESS);
serveAddr.sin_port = htons(PORT);
RET = connect(clientScoket, (struct sockaddr*)&serveAddr, sizeof(serveAddr));
if (RET != 0){
cout << "connect failed \n";
return -1;
}
else cout << "------------------------- Connect successfully -------------------------\n";
//等待消息
h = CreateThread(NULL, 0, ServerThread, (LPVOID)clientScoket, 0, NULL);
while (true){
cin.getline(SendBuffer, sizeof(SendBuffer));
RET = send(clientScoket, SendBuffer, (int)strlen(SendBuffer), 0);
if (RET == SOCKET_ERROR){
cout << "send to error" << endl;
break;
}
}
closesocket(clientScoket);
CloseHandle(h);
WSACleanup();
return 0;
}
#效果显示截图