C++实现客户端/服务端通信(一)

这篇具有很好参考价值的文章主要介绍了C++实现客户端/服务端通信(一)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


网络编程的基本概念

1. 客户端/服务器通信模型:

C++实现客户端/服务端通信(一),c++,开发语言

2. socket函数:

int socket(int domain, int type, int protocol);
1)domain:通讯协议族
PF_INET: IPV4互联网协议族
PF_INET6: IPV6互联网协议族
PF_LOCAL: 本地通信协议族
PF_PACKET: 内核底层的协议族
PF_IPX: IPX Novell协议族
2)type:数据传输类型
SOCK_STREAM: 面向连接的socket
SOCK_DGRAM: 无连接的socket
3)protocol:最终使用的协议
在IPV4互联网协议族中,传输类型为SOCK_STREAM的协议只有IPPROTO_TCP,数据传输方式为SOCK_DGRAM的协议类型只有IPPROTO_UDP
可以填0(编译器自动识别)

3. 主机字节序和网络字节序:

多个字节组成的整数存放涉及到字节序。
大端序:低位字节存在高位,高位字节存在低位(如0X123456内存中存放为12 34 56)
小端序:低位字节存在低位,高位字节存在高位(如0X123456内存中存放为56 34 12),如Intel

为了解决不同字节序的计算机之间传输数据的问题,约定采用网络字节序(大端序)
主机字节序与网络字节序之间的转换:
uint16_t htons(uint16_t hostshort);
uint32_t htonl(uint32_t hostlong);
uint16_t ntohs(uint16_t netshort);
uint32_t ntohl(uint32_t netlong);

4. sockaddr 结构体

存放协议族、端口和地址信息

struct sockaddr {
    unsigned short sa_family;  // 协议族
    unsigned char sa_data[14]; // 14字节的端口和地址
};

5. sockaddr_in 结构体

sockaddr结构体为了统一地址结构的表示方法,统一接口函数,但是操作不方便,所以定义了等价的sockaddr_in结构体,其大小与sockaddr相同,可以强制转换为sockaddr

struct in_addr {
    unsigned int s_addr;       // IP地址,大端序
};

struct sockaddr_in {
    unsigned short sa_family;  // 协议族
    unsigned short sin_port;   // 端口号,大端序
    struct in_addr sin_addr;   // IP地址,32位,只适用于IPV4
    unsigned char sin_zero[8]; // 未使用,为了与sockaddr大小相同
};

之所以搞两个结构体,可能是因为sockaddr可以用于IPV4,后续也可以用于IPV6,sockaddr_in是为了IPV4操作方便(根据sin_addr存放的位数看)。

6. 字符串IP与大端序IP的转换

typedef unsigned int in_addr_t;  // 大端序IP地址

// 将字符串格式的IP转换为大端序IP
in_addr_t inet_addr(const char* cp);
int inet_aton(const char* cp, struct in_addr* inp);

// 将大端序IP转换为字符串格式IP
char *inet_ntoa(struct in_addr in);

实现简单的客户端

功能需求:能够与服务端建立连接,并发送、接收三次信息

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>

using namespace std;

int main(int argc, char** argv)
{
	if (argc < 3) {
		cout << "Error: you should enter server ip and port" << endl;
		cout << "Usage: ./djclient [IP ADDR] [PORT]" << endl;
		return 0;
	}

	int client_socket = socket(AF_INET, SOCK_STREAM, 0);

	struct sockaddr_in server_addr;
	memset(&server_addr, 0, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(atoi(argv[2]));
	struct hostent* server_ip = gethostbyname(argv[1]);   // gethostname支持域名、主机名、字符串
	if (server_ip == nullptr) {
		cout << "gethostbyname failed " << argv[1] << endl;
		close(client_socket);
		return -1;
	}
	memcpy(&server_addr.sin_addr, server_ip->h_addr, server_ip->h_length);

	int ret = connect(client_socket, (struct sockaddr*)&server_addr, sizeof(server_addr));
	if (ret == -1) {
		cout << "connect failed." << endl;
		close(client_socket);
		return -1;
	}

	char buf[1024] = {0};

	// 接受发送消息3次
	for (int i = 0; i < 3; i++) {
		memset(buf, 0, sizeof(buf));
		sprintf(buf, "这是发送的第%d个消息.", i);
		ret = write(client_socket, buf, strlen(buf));
		if (ret == -1) {
			cout << "ERROR: 第 " << i << " 次发送信息失败" << endl;
			break;
		}
		cout << "INFO: 第 " << i << " 次发送了 " << ret << " 个字节,内容为:" << buf << endl;

		memset(buf, 0, sizeof(buf));
		ret = read(client_socket, buf, sizeof(buf) - 1);
		if (ret == -1) {
			cout << "ERROR: 第 " << i << " 次接收信息失败" << endl;
			break;
		}
        
        if (ret == 0) {
 
        }
		cout << "INFO: 第 " << i << " 次接收了 " << ret << " 个字节,内容为:" << buf << endl;
	}

	close(client_socket);

	cout << "通信结束!!!" << endl;
	return 0;
}

实现简单的服务端

功能需求:实现简单的服务端,接收客户端连接,打印接收和连接信息

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>

using namespace std;

int main(int argc, char** argv)
{
	int server_socket = socket(AF_INET, SOCK_STREAM, 0);
	
	struct sockaddr_in server_addr;
	memset(&server_addr, 0, sizeof(server_addr));

	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	server_addr.sin_port = htons(3560);

	int ret = bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr));
	if (ret != 0) {
		cout << "ERROR: bind() 执行失败!!!" << endl;
		close(server_socket);
		return -1;
	}

	ret = listen(server_socket, 5);
	if (ret != 0) {
		cout << "ERROR: listen() 执行失败!!!" << endl;
		close(server_socket);
		return -1;
	}

	// int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen); 
	struct sockaddr_in cliaddr;
	memset(&cliaddr, 0, sizeof(cliaddr));
	socklen_t addrlen = sizeof(cliaddr);

	cout << "等待连接..." << endl;
	int client_socket = accept(server_socket, (struct sockaddr*)&cliaddr, &addrlen);

	char* client_ip = inet_ntoa(cliaddr.sin_addr);

	cout << "INFO: 来自客户端的连接为:" << client_ip << ":"
		 << ntohs(cliaddr.sin_port) << endl;


	char buf[1024] = {0};
	int i = 0;
	while (true) {
		memset(buf, 0, sizeof(buf));
		ret = read(client_socket, buf, sizeof(buf) - 1);
		if (ret == -1) {
			cout << "ERROR: 第 " << i << " 次接收信息失败" << endl;
			break;
		}

		if (ret == 0) {
			cout << "INFO: 客户端断开连接" << endl;
			break;
		}
		cout << "INFO: 第 " << i << " 次接收了 " << ret << " 个字节,内容为:" << buf << endl;

		strcpy(buf, "success!!!");
		ret = write(client_socket, buf, strlen(buf));
		if (ret == -1) {
			cout << "ERROR: 第 " << i << " 次发送信息失败" << endl;
			break;
		}
		cout << "INFO: 第 " << i << " 次发送了 " << ret << " 个字节,内容为:" << buf << endl;
		
		i++;
	}

	close(client_socket);
	close(server_socket);
	return 0;
}

执行结果如下所示:

# 客户端
[root@localhost code]# g++ djclient.cpp -o djclient
[root@localhost code]# ./djclient 
Error: you should enter server ip and port
Usage: ./djclient [IP ADDR] [PORT]
[root@localhost code]# ./djclient 192.168.66.124 3560
INFO: 第 0 次发送了 29 个字节,内容为:这是发送的第0个消息.
INFO: 第 0 次接收了 10 个字节,内容为:success!!!
INFO: 第 1 次发送了 29 个字节,内容为:这是发送的第1个消息.
INFO: 第 1 次接收了 10 个字节,内容为:success!!!
INFO: 第 2 次发送了 29 个字节,内容为:这是发送的第2个消息.
INFO: 第 2 次接收了 10 个字节,内容为:success!!!
通信结束!!!
[root@localhost code]# 

# 服务端
[root@centos server]# g++ djserver.cpp -o djserver
[root@centos server]# ./djserver 
等待连接...
INFO: 来自客户端的连接为:192.168.91.153:14098
INFO: 第 0 次接收了 29 个字节,内容为:这是发送的第0个消息.
INFO: 第 0 次发送了 10 个字节,内容为:success!!!
INFO: 第 1 次接收了 29 个字节,内容为:这是发送的第1个消息.
INFO: 第 1 次发送了 10 个字节,内容为:success!!!
INFO: 第 2 次接收了 29 个字节,内容为:这是发送的第2个消息.
INFO: 第 2 次发送了 10 个字节,内容为:success!!!
INFO: 客户端断开连接
[root@centos server]# 

总结

C++实现客户端/服务端通信(一)基于socket通信的基本API,实现了客户端/服务端的基本通信框架。文章来源地址https://www.toymoban.com/news/detail-677249.html

到了这里,关于C++实现客户端/服务端通信(一)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 网络编程-Socket通信实现服务器与客户端互传文件(JAVA语言实现)

    在网络通信协议下,实现网络互连的不同计算机上运行的程序间可以进行数据交换. 网络编程三要素:ip地址、端口、协议 ip地址: 每台计算机指定的一个标识符,127.0.0.1是回送地址,可以代表本机地址 ,一般用来测试使用 ipconfig:命令行中查看本机地址 ping ip地址:检查网络是

    2023年04月14日
    浏览(47)
  • C++网络编程 TCP套接字基础知识,利用TCP套接字实现客户端-服务端通信

    流式套接字编程针对TCP协议通信,即是面向对象的通信,分为服务端和客户端两部分。 1)加载套接字库( 使用函数WSAStartup() ),创建套接字( 使用socket() ) 2)绑定套接字到一个IP地址和一个端口上( 使用函数bind() ) 3)将套接字设置为监听模式等待连接请求( 使用函数

    2024年02月03日
    浏览(60)
  • UDP服务端和客户端通信代码开发流程

    TCP: 传输控制协议,面向连接的,稳定的,可靠的,安全的数据集流传递 稳定和可靠:丢包重传 数据有序:序号和确认序号 流量控制:稳定窗口 UDP :用户数据报协议 面向无连接的,不稳定的,不可靠,不安全的数据报传递=---更像是收发短信,UDP传输不需要建立连接,传输效率更高

    2024年02月06日
    浏览(46)
  • C++网络通信实例(TCP/IP协议,包括服务端与客户端通信)

    创作不易 觉得有帮助请点赞关注收藏 TCP/IP是当下网络协议栈中的主流协议 TCP属于传输层的协议  可靠传输 包括经典的三次握手等等 IP协议是网络层协议 尽全力传输但不可靠 学过计算机网络的同学们对这个应该比较熟悉 以下是使用C++进行网络通信的实例  服务端 主要使用

    2024年02月14日
    浏览(50)
  • TCP实现服务器和客户端通信

    目录 TCP介绍 代码实现 server(服务器端) 代码分析 client(客户端) 代码分析 结果展示 TCP (Transmission Control Protocol) 是一种面向连接的协议,用于在计算机网络中传输数据。TCP 可以确保数据的可靠传输,即使在网络环境不稳定的情况下也能够保证数据的完整性和顺序。以下是

    2024年02月15日
    浏览(62)
  • SpringBoot集成WebSocket实现客户端与服务端通信

    话不多说,直接上代码看效果! 一、服务端: 1、引用依赖 2、添加配置文件 WebSocketConfig 3、编写WebSocket服务端接收、发送功能   声明接口代码:   实现类代码: 4、如果不需要实现客户端功能,此处可选择前端调用,奉上代码 二、客户端: 1、引用依赖 2、自定义WebSocket客

    2024年01月23日
    浏览(54)
  • TCP通信实现客户端向服务器发送图片

    TCP通信: 1. TCP 协议通信交互流程: 具体的流程如下: (1)服务器根据地址类型(ipv4、ipv6)、socket 类型、协议创建 socket. (2)服务器为 socket 绑定 ip 地址和端口号。 (3)服务器 socket 监听端口号的请求,随时准备接受来自客户端的连接,此时服务器的 socket 处于关闭状态

    2024年02月13日
    浏览(59)
  • QT实现TCP通信(服务器与客户端搭建)

    创建一个QTcpServer类对象,该类对象就是一个服务器 调用listen函数将该对象设置为被动监听状态,监听时,可以监听指定的ip地址,也可以监听所有主机地址,可以通过指定端口号,也可以让服务器自动选择 当有客户端发来连接请求时,该服务器会自动发射一个newConnection信号

    2024年02月09日
    浏览(56)
  • 【手把手做ROS2机器人系统开发五】使用C++实现编写简单的服务器和客户端

    目录 使用C++实现编写简单的服务器和客户端 一、程序编写 1、创建软件包  2、编译软件包 3、软件配置 4、服务器程序编写 5、客户端程序编写 6、软件包设置 7、设置编译选项 二、程序测试 1、编译程序 2、开启节点测试运行 3、执行效果展示          上一讲我们讲解了如

    2024年02月10日
    浏览(43)
  • Python3实现WebSocket服务端与客户端通信

    Python3实现WebSocket服务端与客户端通信 WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信更加轻便、高效,比传统的HTTP通信更省流量和更快速,因此在Web应用领域越来越受欢迎。Python 3提供了内置的websocket库,可以方便地实现WebSocket服务端和客户端的通信。

    2024年02月12日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包