C++ windows TCP和UDP通信学习

一、前言

        本章主要总结 C++ windows 下tcp和 udp通信的一些要点

二、原理

        可参考两张简单的通信流程图

  (1)tcp的通信过程

(2)UDP的通信过程

三、TCP代码

服务端

//sever_tcp.cpp
//导入模块
#include <string>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <WinSock2.h>
#include <Windows.h>
#include <WS2tcpip.h>
//加载lib
#pragma comment(lib, "ws2_32.lib")  //加载 ws2_32.dll
//使用命名空间
using namespace std;


int main() {
	//初始化 DLL
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);

	//创建套接字
	SOCKET servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

	//绑定套接字
	sockaddr_in sockAddr;
	memset(&sockAddr, 0, sizeof(sockAddr));  //每个字节都用0填充
	sockAddr.sin_family = PF_INET;  //使用IPv4地址
	//sockAddr.sin_addr.s_addr = inet_addr("192.168.101.7");  //具体的IP地址
	sockAddr.sin_port = htons(1234);  //端口
	inet_pton(sockAddr.sin_family, "127.0.0.1", &sockAddr.sin_addr.s_addr);
	bind(servSock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));

	//进入监听状态
	listen(servSock, 20);

	//接收客户端请求
	SOCKADDR clntAddr;
	int nSize = sizeof(SOCKADDR);
	SOCKET clntSock = accept(servSock, (SOCKADDR*)&clntAddr, &nSize);
	while (true)
	{
		printf("输入要发送的数据(要退出输入exit):");
		//向客户端发送数据
		string str;
		getline(cin, str);
		if (str != "exit") send(clntSock, ("k" + str + "k").c_str(), str.size() + sizeof(char), NULL);
		else
		{
			send(clntSock, "exit", 4 + sizeof(char), NULL);
			break;
		}
	}
	printf("成功退出!\n");
	//关闭套接字
	closesocket(clntSock);
	closesocket(servSock);

	//终止 DLL 的使用
	WSACleanup();

	return 0;
}

客户端

//client_tcp.cpp
//导入模块
#include <string>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <WinSock2.h>
#include <Windows.h>
#include <WS2tcpip.h>
//加载lib
#pragma comment(lib, "ws2_32.lib")  //加载 ws2_32.dll
//使用命名空间
using namespace std;


int main() {
	//初始化DLL
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);
	//创建套接字
	SOCKET sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	//向服务器发起请求
	sockaddr_in sockAddr;
	memset(&sockAddr, 0, sizeof(sockAddr));  //每个字节都用0填充
	sockAddr.sin_family = PF_INET;
	//sockAddr.sin_addr.s_addr = inet_addr("192.168.101.7");
	sockAddr.sin_port = htons(1234);
	inet_pton(sockAddr.sin_family, "127.0.0.1", &sockAddr.sin_addr.s_addr);
	connect(sock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));
	while (true)
	{
		//接收服务器传回的数据
		char szBuffer[MAXBYTE] = { 0 };
		int can = recv(sock, szBuffer, MAXBYTE, NULL);  
		string buffer = szBuffer;
		if (buffer == "exit")
		{
			printf("对方关闭了Socket。\n");
			//关闭套接字
			closesocket(sock);
			//终止使用 DLL
			WSACleanup();
			system("pause");
			return 0;
		}
		//输出接收到的数据
		if (can > 0) {
			printf("从server接收到的数据: %s\n", buffer.size() > 2 ? buffer.substr(1, buffer.size() - 1).c_str() : "");
		}
		
	}
	return 0;
}

运行结果

四、UDP代码

服务端,相比较于TCP ,UDP客户端无需 connect ,服务端也无需accept ,socket套接字初始化,TCP的是 SOCK_STREAM 而UDP的是 SOCK_DGRAM,UDP接收和发送用的是recvfrom 和 sendto , TCP用的是recv和send

//sever_udp.cpp
//导入模块
#include <string>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <WinSock2.h>
#include <Windows.h>
#include <WS2tcpip.h>
//加载lib
#pragma comment(lib, "ws2_32.lib")  //加载 ws2_32.dll
//使用命名空间
using namespace std;


int main() {
	//初始化 DLL
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);

	//创建套接字
	SOCKET servSock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);  // TCP是 SOCK_STREAM udp是 SOCK_DGRAM,不一样

	//绑定套接字
	sockaddr clientAddr;
	sockaddr_in sockAddr;
	memset(&sockAddr, 0, sizeof(sockAddr));  //每个字节都用0填充
	sockAddr.sin_family = PF_INET;  //使用IPv4地址
	//sockAddr.sin_addr.s_addr = inet_addr("192.168.101.7");  //具体的IP地址
	sockAddr.sin_port = htons(1314);  //端口
	inet_pton(sockAddr.sin_family, "127.0.0.1", &sockAddr.sin_addr.s_addr);
	if(-1 == bind(servSock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR)) )
	{
		printf("bind error!\n");
		//exit(1);
	}
	

	//进入监听状态
	//listen(servSock, 20);  //udp不用 listen

	//接收客户端请求
	SOCKADDR clntAddr;
	int nSize = sizeof(SOCKADDR);
	//SOCKET clntSock = accept(servSock, (SOCKADDR*)&clntAddr, &nSize);  UDP的服务端不用accept ,客户端不用 connect
	while (true)
	{
		char szBuffer[MAXBYTE] = { 0 };
		int str_len = recvfrom(servSock, szBuffer, MAXBYTE, 0, &clientAddr, &nSize);
		if (str_len < 0) continue;
		printf("从server接收到的数据: %s\n", szBuffer);

		printf("输入要发送的数据(要退出输入exit):");
		//向客户端发送数据
		string str;
		getline(cin, str);
		if (str != "exit") 
			//send(clntSock, ("k" + str + "k").c_str(), str.size() + sizeof(char), NULL);
			sendto(servSock, ("k" + str + "k").c_str(), str.size(), 0, &clientAddr, sizeof(SOCKADDR) );
		else
		{
			sendto(servSock, "exit", 4 + sizeof(char), 0, &clientAddr, sizeof(SOCKADDR));  
			break;
		}
	}
	printf("成功退出!\n");
	//关闭套接字
	 
	closesocket(servSock);

	//终止 DLL 的使用
	WSACleanup();

	return 0;
}
//client_udp.cpp
//导入模块
#include <string>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <WinSock2.h>
#include <Windows.h>
#include <WS2tcpip.h>
//加载lib
#pragma comment(lib, "ws2_32.lib")  //加载 ws2_32.dll
//使用命名空间
using namespace std;


int main() {
	//初始化DLL
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);
	//创建套接字
	SOCKET sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);// TCP是 SOCK_STREAM udp是 SOCK_DGRAM,不一样
	//向服务器发起请求
	sockaddr serverAddr;
	int serverAddrLen = 0;
	sockaddr_in sockAddr;
	memset(&sockAddr, 0, sizeof(sockAddr));  //每个字节都用0填充
	sockAddr.sin_family = PF_INET;
	//sockAddr.sin_addr.s_addr = inet_addr("192.168.101.7");
	sockAddr.sin_port = htons(1314);
	inet_pton(sockAddr.sin_family, "127.0.0.1", &sockAddr.sin_addr.s_addr);

	//connect(sock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));  UDP是不用先connect服务端的
	serverAddrLen = sizeof(serverAddr);
	while (true)
	{
		//接收服务器传回的数据
		char szBuffer[MAXBYTE] = { 0 };
		//int can = recv(sock, szBuffer, MAXBYTE, NULL); 

		printf("请输入一个字符串,发送给服务端:");
		string str;
		getline(cin, str);
		sendto(sock, ("k" + str + "k").c_str(), str.size(), 0, (struct sockaddr*)&sockAddr, sizeof(sockAddr));

		int can = recvfrom(sock, szBuffer, MAXBYTE, 0, &serverAddr, &serverAddrLen );
		string buffer = szBuffer;
		if (buffer == "exit")
		{
			printf("对方关闭了Socket。\n");
			//关闭套接字
			closesocket(sock);
			//终止使用 DLL
			WSACleanup();
			system("pause");
			return 0;
		}
		//输出接收到的数据
		if (can > 0) {
			
			printf("从server接收到的数据: %s\n", buffer.size() > 2 ? buffer.substr(1, buffer.size() - 1).c_str() : "");
			memset(szBuffer, 0, MAXBYTE );   // 重置缓冲区
		}
		
	}
	return 0;
}

效果图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值