提到网络编程我们首先想到的是socket,俗称套接字,他将端口和ip进行连接, 然后是winsock,是windows提供的一款网络编程接口。分为1和2两个版本,版本1只提供tcp和udp协议。
tcp和udp是网络通讯基本协议,tcp协议需要三次招手,要求稳定的连接,如同和服务器要有夫妻的名分,udp直接发送到服务器,一夜情
关于c++的网络编程,微软提供了进行操作的程序接口
先说服务器端
- socket()
- bind()
- listen()
- accept()
- recv()/send()
- close()
这就是大致流程,先创建套接字,连接ip和端口,开放访问,再是等待客户端的访问,然后接受访问,保存消息,发送反馈
//winsock是windows提供的一款网络编程接口。分为1和2两个版本,版本1只提供tcp和udp协议
//tcp协议需要稳定链接到服务器,所以说要三次招手
//udp直接打包到网络上发送,不需要链接
#include<WinSock2.h>
//windows.h需要在winsock下面包含
#include<Windows.h>
//网络分为cs和bs'两种模式,cs是客户端和服务器交互,bs是游览器和服务器交互
#include<iostream>
#pragma comment(lib,"ws2_32.lib")
#include<WS2tcpip.h>
int main()
{
//1.初始化网络环境
//第一个参数 sock版本号
//WSAStartup(0X0202);
WSADATA date{ 0 };
WSAStartup(MAKEWORD(2,2),&date);
//2 创建SOCKET
//参数1 地址系列
//参数二 套接类型
//参数三 传输协议
SOCKET server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//3 绑定端口号和IP地址,让客户端可以链接
//使用sockaddr_in结构体保存端口和ip
sockaddr_in serverAddr{ 0 };
serverAddr.sin_family = AF_INET;
//绑定端口 需要用htons转换
serverAddr.sin_port = htons(8888);
//绑定ip地址
inet_pton(AF_INET, "10.212.37.134", &serverAddr.sin_addr);
//全部链接到服务器
//参数1 socket对象 参数2 sockaddr_in结构体地址转SOCKADDR 参数3 结构体大小
bind(server, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
//4 监听
// 参数2 挂起的连接队列的最大长度。 如果设置为 SOMAXCONN,则负责套接字 的基础 服务提供商会将积压工作设置为最大合理值
listen(server, SOMAXCONN);
while (1)
{
//5 接受会话
//客户地址
sockaddr_in clientAddr{ 0 };
int size = sizeof(clientAddr);
printf("等待客户端连接中..........");
//接收客户端
//这是阻塞函数,直到等到客户端发送消息
SOCKET client = accept(server, (SOCKADDR*)&clientAddr, &size);
char buff[0x100]{ 0 };
//保存客户端发送消息
recv(client, buff, 0x100, 0);
printf("客户端说:%s\n", buff);
send(client, "收到消息", 20, 0);
}
closesocket(server);
return 0;
}
这是简单的服务端
然后是客户端
- socket()
- connect()
- send()/recv()
- close()
创建套接字,绑定需要访问的服务器的ip和端口,发送消息,接受反馈,关闭客户端
//winsock是windows提供的一款网络编程接口。分为1和2两个版本,版本1只提供tcp和udp协议
//tcp协议需要稳定链接到服务器,所以说要三次招手
//udp直接打包到网络上发送,不需要链接
#include<WinSock2.h>
//windows.h需要在winsock下面包含
#include<Windows.h>
//网络分为cs和bs'两种模式,cs是客户端和服务器交互,bs是游览器和服务器交互
#include<iostream>
#pragma comment(lib,"ws2_32.lib")
#include<WS2tcpip.h>
int main()
{
//1.初始化网络环境
//第一个参数 sock版本号
//WSAStartup(0X0202);
WSADATA date{ 0 };
WSAStartup(MAKEWORD(2, 2), &date);
//2 创建SOCKET
//参数1 地址系列
//参数二 套接类型
//参数三 传输协议
SOCKET client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//3 绑定端口号和IP地址,让客户端可以链接
//使用sockaddr_in结构体保存端口和ip
sockaddr_in serverAddr{ 0 };
serverAddr.sin_family = AF_INET;
//绑定端口 需要用htons转换
serverAddr.sin_port = htons(8888);
//绑定ip地址
inet_pton(AF_INET, "10.212.37.134", &serverAddr.sin_addr);
int ret = connect(client, (SOCKADDR*)(&serverAddr), sizeof(serverAddr));
if (ret != 0)
{
printf("连接服务器失败");
}
//参数三 发送的输出指针缓冲区
send(client, "客户端发送的消息", 16, 0);
system("pause");
return 0;
}
这是最简单的服务器和客户端交互,只能支持一对一的交互,那么如何让服务器支持多客户端多线程交互呢
多线程交互,多人聊天
服务器端
#include<WinSock2.h>
//windows.h需要在winsock下面包含
#include<Windows.h>
//网络分为cs和bs'两种模式,cs是客户端和服务器交互,bs是游览器和服务器交互
#include<iostream>
#pragma comment(lib,"ws2_32.lib")
#include<WS2tcpip.h>
#include<vector>
using std::vector;
//创建一个容器,存放SOCKET
vector<SOCKET> clientList;
DWORD WINAPI ThreadProc(
_In_ LPVOID param
);
int main()
{
//1.初始化网络环境
//第一个参数 sock版本号
//WSAStartup(0X0202);
WSADATA date{ 0 };
WSAStartup(MAKEWORD(2,2),&date);
//2 创建SOCKET
//参数1 地址系列
//参数二 套接类型
//参数三 传输协议
SOCKET server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//3 绑定端口号和IP地址,让客户端可以链接
//使用sockaddr_in结构体保存端口和ip
sockaddr_in serverAddr{ 0 };
serverAddr.sin_family = AF_INET;
//绑定端口 需要用htons转换
serverAddr.sin_port = htons(8888);
//绑定ip地址
inet_pton(AF_INET, "10.212.37.134", &serverAddr.sin_addr);
//全部链接到服务器
//参数1 socket对象 参数2 sockaddr_in结构体地址转SOCKADDR 参数3 结构体大小
bind(server, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
//4 监听
// 参数2 挂起的连接队列的最大长度。 如果设置为 SOMAXCONN,则负责套接字 的基础 服务提供商会将积压工作设置为最大合理值
listen(server, SOMAXCONN);
while (1)
{
//5 接受会话
//客户地址
sockaddr_in clientAddr{ 0 };
int size = sizeof(clientAddr);
printf("等待客户端连接中..........");
//接收客户端
//这是阻塞函数,直到等到客户端发送消息
SOCKET client = accept(server, (SOCKADDR*)&clientAddr, &size);
//存储client 查看有多少人连接着服务器
clientList.push_back(client);
//创建线程
CreateThread(NULL, NULL, ThreadProc, (LPVOID)client, NULL, NULL);
printf("服务端%u连接上了服务器\n", client);
}
closesocket(server);
return 0;
}
//线程处理函数
DWORD WINAPI ThreadProc(
_In_ LPVOID param
)
{
SOCKET client = (SOCKET)param;
char buff[0x100] = { 0 };
int recvSize;
//保存客户端发送消息
recv(client, buff, 0x100, 0);
while ((recvSize = recv(client, buff, 0x100, 0)) > 0)
{
//遍历vector,查看多少人连接服务器
for (int i = 0; i < clientList.size();i++)
{
if (clientList[i] != client)
{ //向非自身的客户端发送消息
send(clientList[i], buff, recvSize, 0);
}
}
}
//跳出while循环,说明客户端离线,那就删除客户端节点
for (int i = 0; i < clientList.size(); i++)
{
if (clientList[i] == client)
{
printf("客户端%u断开连接\n", clientList[i]);
closesocket(clientList[i]);
clientList.erase(clientList.begin() + i);
}
}
return 0;
};
在这里面我们把客户端消息的处理放在了线程处理函数里面执行,由vector遍历已经连接的客户端,然后发送消息,达到消息同步的目的
客户端
#include<WinSock2.h>
//windows.h需要在winsock下面包含
#include<Windows.h>
//网络分为cs和bs'两种模式,cs是客户端和服务器交互,bs是游览器和服务器交互
#include<iostream>
#pragma comment(lib,"ws2_32.lib")
#include<WS2tcpip.h>
DWORD WINAPI reveMEssage(LPVOID param);
int main()
{
//1.初始化网络环境
//第一个参数 sock版本号
//WSAStartup(0X0202);
WSADATA date{ 0 };
WSAStartup(MAKEWORD(2, 2), &date);
//2 创建SOCKET
//参数1 地址系列
//参数二 套接类型
//参数三 传输协议
SOCKET client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//3 绑定端口号和IP地址,让客户端可以链接
//使用sockaddr_in结构体保存端口和ip
sockaddr_in serverAddr{ 0 };
serverAddr.sin_family = AF_INET;
//绑定端口 需要用htons转换
serverAddr.sin_port = htons(8888);
//绑定ip地址
inet_pton(AF_INET, "10.212.37.134", &serverAddr.sin_addr);
int ret = connect(client, (SOCKADDR*)(&serverAddr), sizeof(serverAddr));
if (ret != 0)
{
printf("连接服务器失败");
}
HANDLE hthread=CreateThread(0, 0, reveMEssage, (LPVOID)client, NULL, NULL);
char buff[0x100]{ 0 };
//持续读取客户端输入,如果输入exit则退出
while (scanf_s("%s", buff, 0x100) && strcmp(buff, "exit"))
{
send(client, buff, strlen(buff) + 1,0);
}
closesocket(client);
CloseHandle(hthread);
return 0;
}
DWORD WINAPI reveMEssage(LPVOID param)
{
SOCKET client = (SOCKET)param;
char buff[0x100] = { 0 };
int recvSize;
while ((recvSize = recv(client, buff, 0x100, 0)) > 0)
{
printf("%s", buff);
}
return 0;
}

7575

被折叠的 条评论
为什么被折叠?



