Bootstrap

C++——网络编程接口(TCP连接)

在这里插入图片描述

一、封装socket的recv和send方法

#include <WinSock2.h>
#include <stdio.h>
#include "gyklib.h"

// 确保在包含WinSock2.h之前定义这些宏
#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS

int SocketRecv(int sock, char* buf, int dataSize)
{
	// 目前收到的数据量
	int numsRecvSoFar = 0;
	// 未收到的数据量
	int numsRemainingToRecv = dataSize;
	printf("enter SocketRecv\n");
	// 循环接收数据
	while (true)
	{
		int bytesRead = recv(sock, &buf[numsRecvSoFar], numsRemainingToRecv, 0);
		printf("###bytesRead = %d, numsRecvSoFar = %d, numsRemainingToRecv = %d\n",
			bytesRead, numsRecvSoFar, numsRemainingToRecv);

		if (bytesRead == numsRemainingToRecv)
		{
			return 0;
		}
		else if (bytesRead > 0)
		{
			numsRecvSoFar += bytesRead;
			numsRemainingToRecv -= bytesRead;
			continue;
		}
		else if (bytesRead < 0 && errno == EAGAIN)
		{
			continue;
		}
		else
		{
			return -1;
		}
	}
}

int SocketSend(int sock, char* buf, int dataSize)
{
	// 目前发送的数据量
	int numsSendSoFar = 0;
	// 未发送的数据量
	int numsRemainingToSend = dataSize;
	printf("enter SocketSend\n");
	// 循环接收数据
	while (true)
	{
		int bytesSend = send(sock, &buf[numsSendSoFar], numsRemainingToSend, 0);
		printf("###bytesSend = %d, numsRecvSoFar = %d, numsRemainingToRecv = %d\n",
			bytesSend, numsSendSoFar, numsRemainingToSend);

		if (bytesSend == numsRemainingToSend)
		{
			return 0;
		}
		else if (bytesSend > 0)
		{
			numsSendSoFar += bytesSend;
			numsRemainingToSend -= bytesSend;
			continue;
		}
		else if (bytesSend < 0 && errno == EAGAIN)
		{
			continue;
		}
		else
		{
			return -1;
		}
	}
}

二、服务端

引入静态库如下
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#include <Ws2tcpip.h>
#include "GykLib.h"

// 使用 #pragma comment(lib, "ws2_32.lib") 可以使你的代码更加自包含,因为你不需要依赖外部的项目设置。
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "GykLib.lib")

int main()
{
	printf("TCP Server\n");
	// 1、初始化网络库
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	wVersionRequested = MAKEWORD(2, 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;
	}

	// 3、建立socket连接,AF_INET:表示ipv4协议
	// SOCK_STREAM:表示TCP连接
	SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);
	if (INVALID_SOCKET == sockSrv)
	{
		printf("socket errorno = %d\n", GetLastError());
		return -1;
	}
	// 配置连接参数
	SOCKADDR_IN addrSrv;
	addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	addrSrv.sin_family = AF_INET;
	addrSrv.sin_port = htons(6000);
	// 绑定socket
	if (SOCKET_ERROR == bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)))
	{
		printf("bind errorno = %d\n", GetLastError());
		return -1;
	}
	// 4、监听 listen
	if (SOCKET_ERROR == listen(sockSrv, 5))
	{
		printf("listen errorno = %d\n", GetLastError());
		return -1;
	}

	SOCKADDR_IN addrCli;
	int len = sizeof(SOCKADDR);
	while (TRUE)
	{
		// 5、分配一台分机去处理客户端的连接
		printf("等待客户端连接中...\n");
		SOCKET sockConn = accept(sockSrv, (SOCKADDR*)&addrCli, &len);
		char ip_str[INET6_ADDRSTRLEN];
		const char* ip = InetNtop(AF_INET, &(addrCli.sin_addr), ip_str, INET_ADDRSTRLEN);
		if (ip != NULL) {
			printf("客户端:{%s}连接成功!\n", ip);
		}
		char sendBuf[100]{};
		sprintf_s(sendBuf, 100, "hello");
		// 6、开始通话,收发数据
		int iLen = SocketSend(sockConn, sendBuf, strlen(sendBuf));

		char recvBuf[100]{};
		iLen = SocketRecv(sockConn, recvBuf, 100);
		printf("recvBuf = %s\n", recvBuf);
		// 7、关闭分级
		closesocket(sockConn);
	}

	// 8、关闭总机
	closesocket(sockSrv);
	WSACleanup();
	system("pause");
	return 0;
}

二、客户端

#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#include <Ws2tcpip.h>
// 使用 #pragma comment(lib, "ws2_32.lib") 可以使你的代码更加自包含,因为你不需要依赖外部的项目设置。
#pragma comment(lib, "ws2_32.lib")

int main()
{
	printf("TCP Client\n");
	// 1、初始化网络库
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	wVersionRequested = MAKEWORD(2, 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;
	}

	// 3、建立socket连接,AF_INET:表示ipv4协议
	// SOCK_STREAM:表示TCP连接
	SOCKET sockCli = socket(AF_INET, SOCK_STREAM, 0);

	if (INVALID_SOCKET == sockCli)
	{
		printf("socket errorno = %d\n", GetLastError());
		return -1;
	}

	// 4、配置要连接的服务器
	SOCKADDR_IN addrSrv;
	memset(&addrSrv, 0, sizeof(addrSrv));
	addrSrv.sin_family = AF_INET;
	addrSrv.sin_port = htons(6000);
	// 假设我们有一个 IP 地址的字符串表示
	const char* ip_str = "192.168.1.11";
	if (inet_pton(AF_INET, ip_str, &(addrSrv.sin_addr.s_addr)) <= 0) {
		// 错误处理
		printf("inet_pton errorno = %d\n", GetLastError());
		return -1;
	}

	// 5、连接服务器
	if (SOCKET_ERROR == connect(sockCli, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)))
	{
		printf("connect errorno = %d\n", GetLastError());
		return -1;
	}

	// 6、收发数据
	char recvBuf[100]{};
	int iLen = recv(sockCli, recvBuf, 100, 0);
	printf("recvBuf = %s\n", recvBuf);

	const char sendBuf[100] = "hehehehehe";
	iLen = send(sockCli, sendBuf, 100, 0);

	// 7、关闭套接字
	closesocket(sockCli);
	WSACleanup();
	system("pause");
	return 0;
}
;