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

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

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

  • 网络编程的基本概念
    • 1. 客户端/服务器通信模型:
    • 2. socket函数:
    • 3. 主机字节序和网络字节序:
    • 4. sockaddr 结构体
    • 5. sockaddr_in 结构体
    • 6. 字符串IP与大端序IP的转换
  • 实现简单的客户端
  • 实现简单的服务端
  • 总结


网络编程的基本概念

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

在这里插入图片描述

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位,只适用于IPV4unsigned 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,实现了客户端/服务端的基本通信框架。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/90806.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

k8s 常用命令(四)

12、删除pod中的nginx服务及service [rootmaster ~]# kubectl delete deployment nginx -n kube-public [rootmaster ~]# kubectl delete svc -n kube-public nginx-service 13、查看endpoint的信息 [rootmaster ~]# kubectl get endpoints 14、修改/更新&#xff08;镜像、…

用Cmake build OpenCV后,在VS中查看OpenCV源码的方法(环境VS2022+openCV4.8.0) Part III

用Cmake build OpenCV后&#xff0c;在VS中查看OpenCV源码的方法(环境VS2022openCV4.8.0) Part III 用Cmake build OpenCV后&#xff0c;在VS中查看OpenCV源码的方法&#xff08;环境VS2022openCV4.8.0&#xff09; Part I_松下J27的博客-CSDN博客 用Cmake build OpenCV后&…

从零构建深度学习推理框架-11 Resnet

op和layer结构 在runtime_ir.cpp中&#xff0c;我们上一节只构建了input和output&#xff0c;对于中间layer的具体实现一直没有完成&#xff1a; for (const auto& kOperator : this->operators_) {if (kOperator->type "pnnx.Input") {this->input_o…

十五、模板方法模式

一、什么是模板方法模式 模板方法&#xff08;Template Method&#xff09;模式的定义如下&#xff1a;定义一个操作中的算法骨架&#xff0c;而将算法的一些步骤延迟到子类中&#xff0c;使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。 模板方法模式包含以…

zookeeper 3.8.1安装和入门使用

1、zookeeper环境搭建&#xff08;Windows单机版&#xff09; 1.1、 前提 必须安装jdk 1.8&#xff0c;配置jdk环境变量&#xff0c;步骤略 1.2、安装zookeeper 地址&#xff1a;https://zookeeper.apache.org/ 1.2.1、选择releases版本 1.2.2、下载安装包并解压 1.2.3、配…

成集云 | 钉钉财务费用单同步至畅捷通 | 解决方案

源系统成集云目标系统 方案介绍 财务管理作为企业管理中重要的组成部分&#xff0c;在企业的发展和成长中扮演着重要角色&#xff0c;成集云以钉钉费用单OA审批与畅捷通TCloud系统为例&#xff0c;与钉钉连接器深度融合&#xff0c;通过数据处理和字段匹配实现了费用…

【redis问题】Caused by: io.netty.channel

遇到的问题&#xff1a; 在使用 RedisTemplate 连接 Redis 进行操作的时候&#xff0c;发生了如下报错&#xff1a; 测试代码为&#xff1a; 配置文件&#xff1a; 问题根源&#xff1a; redis没有添加端口映射解决方案&#xff1a; 删除原来的redis容器&#xff0c;添加新…

高忆管理:大盘是什么意思?

随着市场经济的开展&#xff0c;股票、基金等金融出资产品的普及&#xff0c;大盘这个词汇也逐步进入了咱们的生活中。那么&#xff0c;大盘又是什么意思呢&#xff1f; 从基本概念视点来看&#xff0c;大盘是指股票市场全体走势的指标。出资者经过调查大盘指数的改变&#xf…

luckfox pico 使用记录

连接 使用USB转TTL 连接 USB 也要一起插上 在显示控制台窗口上会显示板子的IP地址 USB接上后 会在网络和共享中心发现 以太网2&#xff08;通过RNDIS 通过USB 将板当网卡用,但使用网络共享&#xff0c;无法ping 通外部网&#xff09; 可以不关闭防火墙&#xff08;WIN10 6…

睿趣科技:抖音开网店卖玩具怎么样

近年来&#xff0c;随着社交媒体平台的飞速发展&#xff0c;抖音作为一款短视频分享应用也迅速崭露头角。而在这个充满创业机遇的时代背景下&#xff0c;许多人开始探索在抖音平台上开设网店&#xff0c;尤其是卖玩具类商品&#xff0c;那么抖音开网店卖玩具究竟怎么样呢? 首先…

分享一篇关于如何使用BootstrapVue的入门指南

你想轻松地创建令人惊叹且响应式的在线应用程序吗&#xff1f;使用BootstrapVue&#xff0c;您可以快速创建美观且用户友好的界面。这个开源工具包是基于Vue.js和Bootstrap构建的&#xff0c;非常适合开发现代Web应用程序。本文将介绍其基础知识&#xff0c;让您可以开始使用这…

ChatGPT的局限性及商业化应用限制讨论

首先&#xff0c;ChatGPT仅使用公开可用的信息&#xff0c;这是其第一个局限。如果基础信息缺失、过时、模糊或过于泛化&#xff0c;AI生成的内容就将不会准确。 只有在使用企业内部专有信息和知识创建特定的GPT时&#xff0c;才会出现真正的商业化解决方案。但对企业而言&…