一、网络编程的必要文件
网络编程头文件 #include <WinSock2.h>
库 #pragam comment(lib,“ws2_32.lib”)
c语言头文件 #include <stdio.h> #include <stdlib.h>
二、初始化套接字库,也是服务器和客户端能够连接成功的网络库
WORD wVersionRequested;// WORD(unsigned short) 定义了一个 WORD 类型的变量 wVersionRequested,用来存储请求的 Winsock 版本信息。
WSADATA wsaData;//定义了一个 WSADATA 结构体变量 wsaData,用来接收 Winsock 启动信息
wVersionRequested = MAKEWORD(2, 2);//使用 MAKEWORD() 宏将 Winsock 版本号设置为 2.2,表示请求使用 Winsock 2.2 版本。
int err = WSAStartup(wVersionRequested, &wsaData);//调用 WSAStartup() 函数初始化 Winsock 库,函数返回值将存储在 err 变量中
WSACleanup();//关闭网络库
三、创建TCP套接字
TCP(Transmission Control Protocol)套接字是一种在网络编程中常用的通信机制。在TCP/IP协议中,TCP负责提供可靠的、面向连接的通信服务,而套接字(socket)则是在应用层和传输层之间的接口,用于实现网络通信。
SOCKET sockSrv = socket(AF_INET,SOCK_STREAM,0);
AF_INET:指定了地址族,表示 IPv4 地址族,用于指定套接字的地址格式。
SOCK_STREAM:指定了套接字的类型,表示这是一个面向连接的、可靠的、基于流的 TCP 套接字。
0:表示默认协议,对于 TCP 套接字来说,通常为 0。
closesocket(sockSrv);//关闭套接字
四、分配地址和端口
SOCKADDR_IN addrSrv;//定义了一个 SOCKADDR_IN 结构体变量 addrSrv,用来存储服务器的地址信息,包括 IP 地址和端口号。
addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);// 设置服务器的 IP 地址。INADDR_ANY 表示服务器将会绑定到所有可用的网络接口上,即监听所有网络接口的连接请求。htonl() 函数用于将主机字节序转换为网络字节序。
addrSrv.sin_family = AF_INET;//设置地址族为 IPv4,表示服务器地址采用 IPv4 地址格式。
addrSrv.sin_port = htons(6000);//设置服务器的端口号为 6000,htons() 函数用于将主机字节序的端口号转换为网络字节序。
五、绑定地址
bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR_IN));//套接字 sockSrv 将会与之前设置好的地址信息 addrSrv 进行绑定,这样服务器就会在指定的 IP 地址和端口上监听连接请求。在网络编程中,bind 函数通常用于将套接字与特定的 IP 地址和端口号绑定,以便服务器能够接收客户端的连接请求。
六、服务器端监听客户端请求
listen(sockSrv, 5);//5:表示允许同时连接到这个套接字的最大客户端数量,也被称为backlog。在这种情况下,服务器套接字将开始监听连接请求,并且最多允许 5 个客户端排队等待被接受。
七、接收或者发送客户端的消息
//创建可以保存客户端信息的套接字
SOCKADDR_IN addrCli;//用来存储客户端的地址信息。
int len = sizeof(SOCKADDR);//地址信息的大小
SOCKET sockConn = accept(sockSrv, (SOCKADDR*)&addrCli, &len); //服务器套接字 sockSrv 调用 accept 函数来接受客户端的连接请求。一旦有客户端连接进来,accept 函数会返回一个新的套接字 sockConn,用于与客户端进行通信。同时,客户端的地址信息会存储在 addrCli 中,len 会被更新为客户端地址信息的实际大小。
int msg_size = recv(sockConn, recvBuf, 100, 0); //调用 recv 函数从已连接的套接字 sockConn 中接收数据,并将接收到的数据存储在 recvBuf 中。
sockConn:已连接的套接字,用于与客户端进行通信。
recvBuf:用于存储接收到的数据的缓冲区。
100:要接收的最大字节数,这里是 100 字节。
0:接收数据的标志位,通常设为 0。
msg_size 表示实际接收到的数据的字节数。如果返回值为 0,则表示客户端已关闭连接;如果返回值为 SOCKET_ERROR,则表示接收数据时出现错误。
int msg_size= send(sockConn, sendBuf, strlen(sendBuf),0);//调用 send 函数向已连接的套接字 sockConn 发送数据,发送的数据来自 sendBuf 缓冲区。
sockConn:已连接的套接字,用于与客户端进行通信。
sendBuf:要发送的数据的缓冲区。
strlen(sendBuf):要发送的数据的长度,通过 strlen 函数获取 sendBuf 中的字符串长度。
0:发送数据的标志位,通常设为 0。
msg_size表示实际发送的数据的字节数。如果返回值为 SOCKET_ERROR,则表示发送数据时出现错误。
//头文件和库
#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#pragma comment(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("WSAStartuo 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安装TCP套接字
SOCKET sockSrv = socket(AF_INET,SOCK_STREAM,0);
if (INVALID_SOCKET == sockSrv)
{
printf("socket errornum = %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_IN)))
{
printf("bind error = %d\n", GetLastError());
return -1;
}
//3监听客户端
if (SOCKET_ERROR == listen(sockSrv, 5))//客户端队列有5个,先进先出
{
printf("listen error = %d\n", GetLastError());
return -1;
}
//存储客户端的地址和端口信息
SOCKADDR_IN addrCli;
int len = sizeof(SOCKADDR);
//4等待接收客户端信息、发送信息给客户端
while (true)
{
// 阻塞在这句代码,等待接收
SOCKET sockConn = accept(sockSrv, (SOCKADDR*)&addrCli, &len);//阻塞的位置
//5服务器发信息
char sendBuf[100] = { 0 };
//sprintf_s(sendBuf, 100, "welcome %s to china",inet_ntoa(addrCli.sin_addr));
sprintf_s(sendBuf, 100, "我是服务器,请客户端接收!");
int iLen = send(sockConn, sendBuf, strlen(sendBuf),0);
//服务器接收信息
char recvBuf[100] = { 0 };
iLen = recv(sockConn, recvBuf, 100, 0);
printf("recvBuf = %s", recvBuf);
//6关闭存储客户端信息的套接字
closesocket(sockConn);
}
//7关闭服务器套接字
closesocket(sockSrv);
//8释放网络库
WSACleanup();
system("pause");
return 0;
}