网络编程
- 网络编程
- C/S:客户端/服务器模式:
- B/S:浏览器/服务器架构模式。
- WinSocket:
- Socket传输的定义和其特点
- 实现简易通信
- 服务器端
- 客户端
网络编程
网络分为C/S,B/S两种模式。
C/S:客户端/服务器模式:
服务器端:
首先服务器先启动,并根据客户端请求做出相应的响应。
1、打开一个通信通道,在某一端口接受客户端请求。
2、接受到客户端请求后处理请求并返回信息给客户端。
3、继续等待客户端请求直到关闭服务器。
客户端:
1、打开一个通信通道,并连接到服务器所在主机的特定端口。
2、向服务器发送请求,等待并接收响应,继续发送请求。
3、关闭客户端。
B/S:浏览器/服务器架构模式。
这种架构浏览器是客户端的主要应用软件,主要事物逻辑在服务器实现,前端(浏览器)负责展示。
WinSocket:
Windows Sockets规范是一套开放的、支持多协议的Windows下的网络编程接口。目前实际应用中的Windwos Sockets规范主要有1.1版本和2.2版本,其中1.1版本只支持TCP/IP协议,而2.2支持多协议,并具有良好的向后兼容性。这俩版本对应的头文件分别是: WinSocket.h WinSocket2.h
Socket传输的定义和其特点
所谓socket通常也称作“套接字”,实现服务器和客户端之间的物理连接,并进行数据传输,主要有UDP和TCP两个协议
。
Socket处于网络协议的传输层
。
TCP协议:TCP (Transmission Control Protocol,传输控制协议)是面向连接的协议,也就是说,在收发数据前,必须和对方建立可靠的连接。一个TCP连接必须要经过三次“对话”才能建立起来,其中的过程非常复杂
UDP协议:UDP是一个非连接的协议,传输数据之前源端和终端不建立连接,当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。
在发送端,UDP传送数据的速度仅仅是受应用程序生成数据的速度、计算机的能力和传输带宽的限制;
在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段.
实现简易通信
服务器端
#include<WinSock2.h>
#include<Windows.h>
#include<iostream>
#include<ws2tcpip.h>
#pragma comment(lib,"ws2_32.lib")
#include<vector>
using std::vector;
vector<SOCKET> clientList;//保存多个线程的客户端
DWORD WINAPI revcMessage(LPVOID param)
{
SOCKET client = (SOCKET)param;
char buff[0x100]{ 0 };
int recvSize = 0;
while ((recvSize = recv(client,buff,0x100,0))>0)//接受消息的字节数判断是否大于0
{
for (int i = 0; i < clientList.size(); i++)//遍历进程中的每一个客户端线程
{
if (client != clientList[i])//判断是不是当前线程发的消息,若不是则发送给每个客户端
{
send(clientList[i], buff, recvSize, 0);
}
}
}
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;
}
int main()
{
//1、初始化网络环境
WSADATA data{ 0 };
WSAStartup(MAKEWORD(2,2), &data);
//2、创建Socket
SOCKET server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//用IPv4地址协议簇,TCP连接
//3、指定IP地址和端口号
sockaddr_in serverAddr{ 0 };
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(7777);
inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);//InetPton函数将标准文本表示形式的 IPv4 或 IPv6 互联网网络地址转换为数字二进制形式
//printf("%s\n", serverAddr.sin_addr);
bind(server, (SOCKADDR*)&serverAddr, sizeof(serverAddr));//绑定函数将本地地址与套接字相关联。
//4、监听
listen(server, SOMAXCONN);
//5、接受会话
sockaddr_in clientAddr{ 0 };
int size = sizeof(clientAddr);
while (1)
{
//printf("等待客户端连接中......\n");
SOCKET client = accept(server, (SOCKADDR*)&clientAddr, &size);//绑定将监听地址与套接字
clientList.push_back(client);
//创建线程实现并发通信
CreateThread(NULL, NULL, revcMessage, (LPVOID)client, NULL, NULL);
printf("客户端%u连接到了服务器\n",client);
//char buff[0x100]{ 0 };
//recv(client, buff, 0X100, 0); //recv函数从连接的套接字或绑定的无连接套接字接收数据
//printf("client:%s\n", buff);
//send(client, "有话说,没话走!", 16, 0);
}
closesocket(server);
return 0;
}
客户端
#include<WinSock2.h>
#include<Windows.h>
#include<iostream>
#include<ws2tcpip.h>
#pragma comment(lib,"ws2_32.lib")
DWORD WINAPI revcMessage(LPVOID param)
{
SOCKET client = (SOCKET)param;
char buff[0x100]{ 0 };
while (recv(client, buff, 0x100, 0) > 0)
{
printf("%s\n", buff);
}
return 0;
}
int main()
{
//1、初始化网络环境
WSADATA data{ 0 };
WSAStartup(MAKEWORD(2, 2), &data);
//2、创建Socket
SOCKET client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//用IPv4地址协议簇,TCP连接
//3、指定IP地址和端口号
sockaddr_in serverAddr{ 0 };
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(7777);
inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);//InetPton函数将标准文本表示形式的 IPv4 或 IPv6 互联网网络地址转换为数字二进制形式
//4、连接
int result = connect(client, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
if (result)
{
printf("连接服务器失败\n");
}
HANDLE hThread = CreateThread(NULL, NULL, revcMessage, (LPVOID)client, NULL, NULL);
char buff[0x100]{ 0 };
while (scanf_s("%s",buff,0x100) && strcmp(buff,"exit"))//接受用户输入
{
send(client, buff, strlen(buff) + 1, 0);
}
closesocket(client);
CloseHandle(hThread);
/*send(client, "我有话说\n", 8, 0);
char buff[0x100]{ 0 };
recv(client, buff, 0x100, 0);
printf("server:%s", buff);
system("pause");*/
return 0;
}
若不点击服务器端则一直等待客户端消息。