视频解析:【C/C++网络编程】多客户端聊天室!多线程+网络编程实现多人聊天功能,可以实现多客户端的简单通讯 ~_哔哩哔哩_bilibili
网络视频:socket到底是什么?_哔哩哔哩_bilibili
目录
客户端
服务器端进行网络通信的流程
1.确定协议版本
2.创建Socket
3.确定服务器协议地址簇
4.绑定
5.监听
6.接收客户端链接
7.通信
8.关闭socket
1.确定协议版本
先声明一个WSAData类型的变量
WSAData wsadata;
然后输入:"WSAStartup",选中它,按F1会转到帮助文档. 文档里说明了要使用WSAStartup的要求:
通过MAKEWORD这个宏指定主版本为2,副版本为2的协议:
然后加上判断
WSAStartup(MAKEWORD(2, 2), &wsadata);
if (LOBYTE(wsadata.wVersion) != 2 ||
HIBYTE(wsadata.wVersion) != 2)
{
printf("确定网络协议版本失败!\n");
system("pause");
return -1;
}
else printf("确定网络协议版本成功!\n");
2.创建Socket
这一步照抄
SOCKET socketserver = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if (SOCKET_ERROR == socketserver)
{
printf("创建socket失败,%d\n",GetLastError());
WSACleanup(); //如果失败就把协议清理掉
system("pause");
return -1;
}
else printf("创建socket成功!\n");
3.确定服务器协议地址簇
SOCKADDR_IN就是一个结构体,里面有IP地址,端口号这些成员变量.一个IP地址确定一台主机,端口号确定APP;
SOCKADDR_IN addr = { 0 };
addr.sin_family = AF_INET; //照抄上面的
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //ip地址
addr.sin_port = htons(9527); //端口号
4.绑定
int r = bind(socketserver,(sockaddr*)&addr,sizeof addr);
if (-1== r)
{
printf("绑定失败,%d\n", GetLastError());
WSACleanup(); //如果失败就把协议清理掉
system("pause");
return -1;
}
else printf("绑定成功!\n");
5.监听
r = listen(socketserver,10);
if (-1 == r)
{
printf("监听失败,%d\n", GetLastError());
WSACleanup(); //如果失败就把协议清理掉
system("pause");
return -1;
}
else printf("监听成功!\n");
6.接受客户端连接
SOCKET clientSocket = accept(socketserver, (sockaddr*)NULL, NULL); //后两个参数是客户端的ip,端口号
if (-1 == clientSocket)
{
printf("服务器崩溃,%d\n", GetLastError());
WSACleanup(); //如果失败就把协议清理掉
system("pause");
return -1;
}
else printf("有客户端链接服务器\n");
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)tongxun, (LPVOID)i, NULL, NULL);
7.通信
char buff[56]; //接收客户端发来的信息
while (1)
{
r = recv(clientSocket, buff, 55, NULL); //最多接收55条,因为还要留一个给结束符
if (r > 0) //如果接收到消息了就添加一个结束符
{
buff[r] = 0;
printf(">>%s\n", buff);
}
}
8.关闭socket
closesocket(socketserver);
9.清理协议
WSACleanup();
客户端进行网络通信的流程
1.确定协议版本
2.创建Socket
3.确定服务器协议地址簇
4.连接服务器
5.通信
6.关闭socket
7.清理协议
1,2,3步骤和服务器端一样,第四个步骤如下:
4.连接服务器
int r = connect(socketserver, (sockaddr*)&addr, sizeof addr);
if (-1 == r)
{
printf("连接服务器失败!\n");
WSACleanup(); //如果失败就把协议清理掉
system("pause");
}
else printf("连接服务器成功!\n");
5.通信
//循环接收用户输入,发送给服务器
char buff[56];
while (1)
{
scanf("%s", buff);
send(socketserver, buff, strlen(buff), NULL);
}
6.关闭socket
closesocket(socketserver);
7.清理协议
WSACleanup();
此时,只能做到客户端与服务器端一对一通信:
我们现在想实现多个客户端与服务器端进行通信,就要用到io多路复用,多线程等技术.我们这里用多线程.
我们在接收客户端连接这一部分进行修改:
我们将上文定义的SOCKET clientSocket变为SOCKET clientSocket[].这样就可以接受多条客户端的链接.我们设置一个for循环,在循环中通过下标自增来接受多个客户端链接的请求,代码如下:
for (int i = 0; i < NUM; i++) //可以接受NUM个客户端的链接
{
clientSocket[i] = accept(socketserver, (sockaddr*)NULL, NULL); //后两个参数是客户端的ip,端口号
if (-1 == clientSocket[i])
{
printf("服务器崩溃,%d\n", GetLastError());
WSACleanup(); //如果失败就把协议清理掉
system("pause");
return -1;
}
else printf("有客户端链接服务器\n");
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)tongxun, (LPVOID)i, NULL, NULL);
}
这样我们就可以多个客户端与服务器端进行通信了:
代码整理
客户端
#define _CRT_SECURE_NO_WARNINGS 1
#define _WINSOCK_DEPRECATED_NO_WARNINGS //为了消除警告
#include<stdio.h>
#include <winsock2.h>
#include<windows.h>
#pragma comment(lib, "ws2_32.lib")
int main()
{
//第一步确定协议版本
WSAData wsadata;
WSAStartup(MAKEWORD(2, 2), &wsadata);
if (LOBYTE(wsadata.wVersion) != 2 ||
HIBYTE(wsadata.wVersion) != 2)
{
printf("确定网络协议版本失败!\n");
system("pause");
return -1;
}
else printf("确定网络协议版本成功!\n");
//第二步创建Socket
SOCKET socketserver = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (SOCKET_ERROR == socketserver)
{
printf("创建socket失败,%d\n", GetLastError());
WSACleanup(); //如果失败就把协议清理掉
system("pause");
return -1;
}
else printf("创建socket成功!\n");
//3.确定服务器协议地址簇
SOCKADDR_IN addr = { 0 }; //SOCKADDR_IN就是一个结构体
addr.sin_family = AF_INET; //照抄上面的
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //ip地址
addr.sin_port = htons(9527); //端口号
//4.连接服务器
int r = connect(socketserver, (sockaddr*)&addr, sizeof addr);
if (-1 == r)
{
printf("连接服务器失败!\n");
WSACleanup(); //如果失败就把协议清理掉
system("pause");
}
else printf("连接服务器成功!\n");
//5.通信
//循环接收用户输入,发送给服务器
char buff[56];
while (1)
{
scanf("%s", buff);
send(socketserver, buff, strlen(buff), NULL);
}
//6.关闭socket
closesocket(socketserver);
//7.清理协议
WSACleanup();
return 0;
}
服务器端
#define _CRT_SECURE_NO_WARNINGS 1
#define _WINSOCK_DEPRECATED_NO_WARNINGS //为了消除警告
#include<stdio.h>
#include <winsock2.h>
#include<windows.h>
#pragma comment(lib, "ws2_32.lib")
#define NUM 1024
SOCKET clientSocket[1024];
void tongxun(int idx);
int main()
{
//第一步确定协议版本
WSAData wsadata;
WSAStartup(MAKEWORD(2, 2), &wsadata);
if (LOBYTE(wsadata.wVersion) != 2 ||
HIBYTE(wsadata.wVersion) != 2)
{
printf("确定网络协议版本失败!\n");
system("pause");
return -1;
}
else printf("确定网络协议版本成功!\n");
//第二步创建Socket
SOCKET socketserver = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if (SOCKET_ERROR == socketserver)
{
printf("创建socket失败,%d\n",GetLastError());
WSACleanup(); //如果失败就把协议清理掉
system("pause");
return -1;
}
else printf("创建socket成功!\n");
//3.确定服务器协议地址簇
SOCKADDR_IN addr = { 0 }; //SOCKADDR_IN就是一个结构体
addr.sin_family = AF_INET; //照抄上面的
addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //ip地址
addr.sin_port = htons(9527); //端口号
//4.绑定
int r = bind(socketserver,(sockaddr*)&addr,sizeof addr);
if (-1== r)
{
printf("绑定失败,%d\n", GetLastError());
WSACleanup(); //如果失败就把协议清理掉
system("pause");
return -1;
}
else printf("绑定成功!\n");
//5.监听
r = listen(socketserver,10);
if (-1 == r)
{
printf("监听失败,%d\n", GetLastError());
WSACleanup(); //如果失败就把协议清理掉
system("pause");
return -1;
}
else printf("监听成功!\n");
//6.接收客户端链接
for (int i = 0; i < NUM; i++) //可以接受NUM个客户端的链接
{
clientSocket[i] = accept(socketserver, (sockaddr*)NULL, NULL); //后两个参数是客户端的ip,端口号
if (-1 == clientSocket[i])
{
printf("服务器崩溃,%d\n", GetLastError());
WSACleanup(); //如果失败就把协议清理掉
system("pause");
return -1;
}
else printf("有客户端链接服务器\n");
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)tongxun, (LPVOID)i, NULL, NULL);
}
//8.关闭socket
closesocket(socketserver);
//9.清理协议
WSACleanup();
return 0;
}
void tongxun(int idx)
{
int r;
//7.通信
char buff[56]; //接收客户端发来的信息
while (1)
{
r = recv(clientSocket[idx], buff, 55, NULL); //最多接收55条,因为还要留一个给结束符
if (r > 0) //如果接收到消息了就添加一个结束符
{
buff[r] = 0;
printf(">>%s\n", buff);
}
}
}