此为Windows编程的第一谈!关注我,带你快速通过Windows编程的学习路线!
每一篇的技术点都是很很重要!很重要!很重要!但不冗余!
我们通常采取总-分-总和生活化的讲解方式来阐述一个知识点!
码农不易,各位学者学到东西请点赞支持支持!
开始部分:
总:首先,我们要了解流程(根据此图来理解,并记忆此图)
分:
一、服务端:
1.首先我们是需要初始化Winsock库的:服务器使用WSAStartup函数来初始化Winsock库。此步骤是必须的。就比如电信公司架设电话网络,确保通信的基础设施到位。
2.创建套接字:使用socket函数创建一个TCP套接字。这个套接字用来监听客户端的连接请求。
相当于在公司安装一部电话机,这部电话机可以用来接听客户的电话。
3.bind绑定套接字:将套接字绑定到本地的一个特定的IP地址和端口。相当于给公司的电话机分配一个固定的电话号码,这个号码可以接收来自任何地方的电话。
4.listen监听:使用listen函数使套接字进入监听状态,并指定连接请求的队列长度。相当于公司把电话机设定为接听模式,随时准备接听客户打来的电话。
5.接受连接:服务器进入一个无限循环,使用accept函数来接收客户端的连接,一旦有客户端连接请求到达,accept函数会返回一个新的套接字,这个套接字专门用于与这个客户端通信。
公司电话响了(客户打电话过来了),接线员接起电话,准备与客户沟通。
6.发送欢迎消息:使用send函数向客户端发送一条“Welcome to China”信息。
接线员在接通电话后说“欢迎致电我们公司”。
7.接受信息:使用recv函数接收客户端发送的信息。
接线员听客户说话,记录客户的需求或问题。
8.关闭套接字:通信完成后,关闭为客户端创建的专用套接字。
通话结束后,接线员挂断电话,但电话机继续保持接听模式,准备接听下一个客户的电话。
根据上面的步骤,服务端的代码实现如下:
#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#include <ws2tcpip.h> // 包含inet_ntop的头文件
#pragma comment(lib, "Ws2_32.lib") // 链接Ws2_32.lib
int main()
{
printf("TCP Server\n");
//0.初始化网络库
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0)
{
printf("WSAStartup errorNum = %d\n", GetLastError());
return err;
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
printf("LOBYTE errorNum = %d\n", GetLastError());
WSACleanup();
return -1;
}
//1.安装电话机
SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == sockSrv)
{
printf("socket error = %d\n", GetLastError());
return -1;
}
// 2.分配电话号码,填充参数
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(6000);
if (SOCKET_ERROR == bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)))
{
printf("bind error = %d\n", GetLastError);
return -1;
}
// 3.监听
if (SOCKET_ERROR == listen(sockSrv, 5))
{
printf("listen error = %d\n", GetLastError);
return -1;
}
listen(sockSrv, 5);
SOCKADDR_IN addrCli;
int len = sizeof(SOCKADDR);
while (TRUE)
{
// 4.分配一台分机去处理客户端连接,拿起电话机,准备接听
printf("begin accept\n");
SOCKET sockConn = accept(sockSrv, (SOCKADDR*)&addrCli, &len);
printf("end accept\n");
#define _WINSOCK_DEPRECATED_NO_WARNINGS // 禁用弃用警告
char sendBuf[100] = { 0 };
// 替换为inet_ntop
inet_ntop(AF_INET, &addrCli.sin_addr, sendBuf, sizeof(sendBuf));
sprintf_s(sendBuf, 100, "Welcome %s to China", sendBuf);
// 5.开始通话,发收数据
int iLen = send(sockConn, sendBuf, strlen(sendBuf), 0);
char recvBuf[100] = { 0 };
iLen = recv(sockConn, recvBuf, 100, 0);
printf("recvBuf = %s\n", recvBuf);
// 6.关闭分机
closesocket(sockConn);
}
// 7.关闭总机,这里不应该关闭sockSrv,因为sockSrv是服务端监听的套接字
// closesocket(sockSrv);
WSACleanup(); // 清理Winsock
return 0;
}
二、客户端:
1.初始化Winsock库:客户端也是使用WSAStartup函数来初始化Winsock库。
相当于在家里安装电话网络,确保可以打电话。
2.创建套接字:也是使用socket函数创建一个TCP套接字,这个套接字用于连接服务器。
在家里安装一部电话机,这部电话机可以用来拨打电话。
3.配置服务器的地址:
相当于查找公司的电话号码并输入到电话机中,准备拨号。
4.连接服务器:使用connect函数连接到服务器。
按下拨号键,开始拨打公司的电话号码。
5.接收欢迎信息:连接建立后,使用recv函数来接收服务器的欢迎信息。
电话接通后,听到接线员说“欢迎致电我们公司”。
6.发送响应信息:使用send函数向服务器发送一条响应信息。
客户向接线员说明自己的需求或问题。
7.关闭套接字:通信完成后,关闭套接字。
通话结束后,客户挂断电话。
根据上面的步骤,客户端的代码实现如下:
#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#include <ws2tcpip.h> // 包含inet_ntop的头文件
#pragma comment(lib, "Ws2_32.lib") // 链接Ws2_32.lib
int main()
{
printf("TCP Client\n");
//0.初始化网络库
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0)
{
printf("WSAStartup errorNum = %d\n", GetLastError());
return err;
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
printf("LOBYTE errorNum = %d\n", GetLastError());
WSACleanup();
return -1;
}
//1.安装电话机
SOCKET sockCli = socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == sockCli)
{
printf("socket error = %d\n", GetLastError());
return -1;
}
//2.配置要连接的服务器
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = inet_addr("192.168.0.102");
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(6000);
//3.连接服务器
if (SOCKET_ERROR == connect(sockCli, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)))
{
printf("connect error = %d\n", GetLastError());
system("pause");
return -1;
}
//4.收发数据
char recvBuf[100] = { 0 };
int iLen = recv(sockCli, recvBuf, 100, 0);
printf("recvBuf = %s\n", recvBuf);
char sendBuf[100] = "love is not only";
iLen = send(sockCli, (char*)sendBuf, 100, 0);
//5.关闭套接字
closesocket(sockCli);
system("pause");
}
总:客户端和服务端的代码其实是类似的。