Window下CLion实现本机通过socket通信-C++

1.引言-什么是socket

socket即套接字,用于描述地址和端口,是一个通信链的句柄。应用程序通过socket向网络发出请求或者回应。

sockets(套接字)编程有三种,流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM),原始套接字(SOCK_RAW);前两种较常用。基于TCP的socket编程是采用的流式套接字

有可能多种协议使用同一种数据传输方式,所以在socket编程中,需要同时指明数据传输方式和协议。

2. socket常用函数

2.1 sockaddr_in

struct sockaddr_in这个结构体用来处理网络通信的地址

struct sockaddr_in {short            sin_family;       // 2 bytes e.g. AF_INET, AF_INET6unsigned short   sin_port;    //16位 2 bytes e.g. htons(3490)struct in_addr   sin_addr;     //32位 4 bytes see struct in_addr, belowchar             sin_zero[8];     // 8 bytes zero this if you want to
};
//另一个结构体 in_addr存放32位ip地址
struct in_addr {unsigned long s_addr;          // 4 bytes load with inet_pton()
};

端口号需要用 htons() 函数转换

2.2 htons()、 inet_addr()和inet_ntoa()

htons()作用是将端口号由主机字节序转换为网络字节序的整数值。(host to net)

inet_addr()作用是将一个IP字符串转化为一个网络字节序的整数值,用于sockaddr_in.sin_addr.s_addr。

inet_ntoa()作用是将一个sin_addr结构体输出成IP字符串(network to ascii)。比如:

printf("%s",inet_ntoa(mysock.sin_addr));

htonl()作用和htons()一样,不过它针对的是32位的(long),而htons()针对的是两个字节,16位的(short)。

与htonl()和htons()作用相反的两个函数是:ntohl()和ntohs()。

2.3 socket()

创建套接字

int socket(int af, int type, int protocol);

afIP地址的类型

  • AF_INET : IPv4

  • AF_INET6: IPV6

type:数据传输方式

  • SOCK_STREAM:面向连接的数据传输方式

  • SOCK_DGRAM:无连接的数据传输方式

protocol:传输协议

  • IPPROTO_TCP:TCP传输协议

  • IPPTOTO_UDP:UDP传输协议

返回值

  • 成功:0

  • 失败:-1

2.4 bind()

地址绑定,将套接字与地址关联

int bind(int sockfd, struct sockaddr *addr, socklen_t addrlen);

sockfd:socket文件描述符

addr:sockaddr 结构体变量的指针

addrlen:addr 变量的大小

返回值

  • 成功:0

  • 失败:-1

2.5 connect()

建立连接,创建与指定外部端口的连接

int connect(int sockfd, struct sockaddr *serv_addr, socklen_t addrlen);

sockfd:socket文件描述符

addr:sockaddr 结构体变量的指针

addrlen:addr 变量的大小

返回值

  • 成功:0

  • 失败:-1

2.6 listen()

让套接字进入被动监听状态(指当没有客户端请求时,套接字处于”睡眠“状态,只有当接收到客户端请求时,套接字才会被“唤醒”来响应请求),使得一个进程可以接收其他进程的请求,从而成为一个服务器进程

int listen(int sockfd, int backlog);

sockfd:被监听的套接字的标识符

backlog:请求队列的最大长度(能存放多少个客户端请求)

  • 请求队列:当套接字正在处理客户端请求时,如果有新的请求进来,套接字将把新的请求放入缓冲区,再从缓冲区取出请求 ,此缓冲区称为请求队列

返回值

  • 成功:0

  • 失败:-1

2.7 accept()

在一个套接口接收一个连接,当套接字处于监听状态时,可以通过accept()函数来接受客户端请求,accept()会阻塞程序进行,直到有新的请求到来

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

sockfd:服务器端套接字的标识符

addr:sockaddr 结构体变量的指针

addrlen:addr 变量的大小

返回值

  • 成功:返回接收到的套接字的描述符

  • 失败:-1

2.8 send()

发送数据,将数据由指定的socket传给对方主机

int send(int s, const void * msg, int len, unsigned int falgs);

s:以建立好连接的socket标识符

msg:发送的消息内容

len:发送内容的长度

falgs:一般设为0

返回值

  • 成功:返回实际传送出去的字符数

  • 失败:-1

2.9 recv()

接受数据,接收远端主机经过指定的socket传来的数据,并把数据存到buf指定的内存空间

int recv(int sock, void *buf, int len, unsigned int flags);

sock:接收端套接字描述符

buf:指定缓冲区,存放接收到的数据

len:缓冲区的长度

flags:一般设为0

返回值

  • 成功:返回接收到的字符数

  • 失败:-1

3.客户端/服务端模式

在TCP/IP(Transmission Control Protocol Internet Protocol / 传输控制协议和网际协议,TCP/IP是一种网络协议,由TCP和IP两个协议组成。它负责在计算机网络中传输数据,并确保数据传输的可靠性,同时确定数据在网络中的路径。TCP/IP是网络通信的基础,也是网络上最常用的协议之一)网络应用中,通信的两个进程相互作用的主要模式是客户/服务器模式,即客户端向服务器发出请求,服务器接收请求后,提供相应的服务。因此需要一种机制为希望通信的进程间建立联系,为二者的数据交换提供同步,这就是基于客户/服务端模式的TCP/IP。

3.1 什么是TCP

TCP有三个关键步骤:三次握手,传输确认和四次挥手

构建思路:

服务端:建立socket,声明自身的端口号和地址并绑定到socket,使用listen打开监听,然后不断用accept去查看是否有连接,如果有,捕获socket,并通过recv获取消息的内容,通信完成后调用closeSocket关闭这个对应accept到的socket,如果不再需要等待任何客户端连接,那么用closeSocket关闭掉自身的socket。

客户端:建立socket,通过端口号和地址确定目标服务器,使用Connect连接到服务器,send发送消息,等待处理,通信完成后调用closeSocket关闭socket。

3.2 编程步骤

(1)服务端

1、加载套接字库,创建套接字(WSAStartup()/socket());

2、绑定套接字到一个IP地址和一个端口上(bind());

3、将套接字设置为监听模式等待连接请求(listen());

4、请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept());

5、用返回的套接字和客户端进行通信(send()/recv());

6、返回,等待另一个连接请求;

7、关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup());

(2)客户端

1、加载套接字库,创建套接字(WSAStartup()/socket());

2、向服务器发出连接请求(connect());

3、和服务器进行通信(send()/recv());

4、关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup());

3.3 学习代码

#include <stdio.h>
#include <winsock2.h>#pragma comment(lib, "ws2_32.lib")int main(int argc, char* argv[]) 
{WORD sockVersion = MAKEWORD(2, 2);WSADATA wsaData;if (WSAStartup(sockVersion, &wsaData) != 0){return 0;}SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (slisten == INVALID_SOCKET){printf("socket error !");return 0;}sockaddr_in sin;sin.sin_port = htons(8888);sin.sin_family = AF_INET;sin.sin_addr.S_un.S_addr = INADDR_ANY;if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR){printf("bind error !");}if (listen(slisten, 5) == SOCKET_ERROR){printf("listen error !");return 0;}SOCKET sClient;sockaddr_in remoteAddr;int nAddrlen = sizeof(remoteAddr);char revData[255];while (true){printf("Wating for connecting... \r\n");sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);if (sClient == INVALID_SOCKET){printf("accept error !");continue;}printf("accept a connection: %s \r\n", inet_ntoa(remoteAddr.sin_addr));int ret = recv(sClient, revData, 255, 0);if (ret > 0){revData[ret] = 0x00;printf(revData);}const char * sendData = "hello, TCP Client";send(sClient, sendData, strlen(sendData), 0);closesocket(sClient);}closesocket(slisten);WSACleanup();return 0;
}

client.cpp

#include <WINSOCK2.H>
#include <STDIO.H>
#include <iostream>
#include <cstring>
using namespace std;
#pragma comment(lib, "ws2_32.lib")int main()
{WORD sockVersion = MAKEWORD(2,2);WSADATA data;if (WSAStartup(sockVersion, &data) != 0){return 0;}while (true){SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (sclient == INVALID_SOCKET){printf("Invalid socket!");return 0;}sockaddr_in serAddr;serAddr.sin_family = AF_INET;serAddr.sin_port = htons(8888);serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR){printf("connect error!");closesocket(sclient);return 0;}string data;cin>>data;const char * sendData;sendData = data.c_str();send(sclient, sendData, strlen(sendData), 0);char recData[255];int ret = recv(sclient, recData, 255, 0);if (ret > 0){recData[ret] = 0x00;printf(recData);}closesocket(sclient);}WSACleanup();return 0;
}

3.4 客户端一直发送数据代码

server.cpp

#include <stdio.h>
#include <winsock2.h>#pragma comment(lib, "ws2_32.lib")int main(int argc, char* argv[])
{WORD sockVersion = MAKEWORD(2,2);WSADATA wsadata;if (WSAStartup(sockVersion, &wsadata) != 0){return 0;}SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (slisten == INVALID_SOCKET){printf("socket error!");return 0;}sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(6000);sin.sin_addr.S_un.S_addr = INADDR_ANY;if(bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR){printf("bind error!");return 0;}if (listen(slisten, 5) == SOCKET_ERROR){printf("listen error!");return 0;}SOCKET sClient;sockaddr_in remoteAddr;int nAddrlen = sizeof(remoteAddr);char revData[255];while (true){printf("Waiting for connecting... \n");sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);if (sClient == SOCKET_ERROR){printf("accept error !");continue;}int ret = recv(sClient, revData, 255, 0);if (ret > 0 ){revData[ret] = 0x00;printf("Received: %s\n", revData);}const char * sendData = "Hello World from Server";send(sClient, sendData, strlen(sendData), 0);printf("Sent: %s\n", sendData);// Keep receiving messageswhile (true){ret = recv(sClient, revData, 255, 0);if (ret > 0){revData[ret] = 0x00;printf("Received: %s\n", revData);}}closesocket(sClient);}closesocket(slisten);WSACleanup();return 0;
}

client.cpp

#include <winsock2.h>
#include <stdio.h>
#include <iostream>
#include <cstring>#pragma comment(lib, "ws2_32.lib")int main()
{WORD sockVersion = MAKEWORD(2,2);WSADATA data;if(WSAStartup(sockVersion, &data) != 0){return 0;}SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if(sclient == INVALID_SOCKET){printf("Invalid socket!");return 0;}sockaddr_in serAddr;serAddr.sin_family = AF_INET;serAddr.sin_port = htons(6000);serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR){printf("connect error!");closesocket(sclient);return 0;}const char * sendData = "Hello World from Client";send(sclient, sendData, strlen(sendData), 0);printf("Sent: %s\n", sendData);char recData[255];int ret = recv(sclient, recData, 255, 0);if (ret > 0){recData[ret] = 0x00;printf("Received: %s\n", recData);}// Keep sending messageswhile (true){const char * helloData = "Hello";send(sclient, helloData, strlen(helloData), 0);printf("Sent: %s\n", helloData);// Sleep for 1 secondSleep(1000);}closesocket(sclient);WSACleanup();return 0;
}

3.5 用户在客户端输入数据代码

server.cpp

#include <stdio.h>
#include <winsock2.h>#pragma comment(lib, "ws2_32.lib")int main(int argc, char* argv[])
{WORD sockVersion = MAKEWORD(2,2);WSADATA wsadata;if (WSAStartup(sockVersion, &wsadata) != 0){return 0;}SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (slisten == INVALID_SOCKET){printf("socket error!");return 0;}sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(6000);sin.sin_addr.S_un.S_addr = INADDR_ANY;if(bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR){printf("bind error!");return 0;}if (listen(slisten, 5) == SOCKET_ERROR){printf("listen error!");return 0;}SOCKET sClient;sockaddr_in remoteAddr;int nAddrlen = sizeof(remoteAddr);char revData[255];while (true){printf("Waiting for connecting... \n");sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);if (sClient == SOCKET_ERROR){printf("accept error !");continue;}// Keep receiving messageswhile (true){int ret = recv(sClient, revData, 255, 0);if (ret > 0){revData[ret] = 0x00;printf("Received: %s\n", revData);}else if (ret == 0) // Connection closed{printf("Client disconnected.\n");closesocket(sClient);break;}else if (ret == SOCKET_ERROR) // Error receiving{printf("recv error!\n");closesocket(sClient);break;}}}closesocket(slisten);WSACleanup();return 0;
}

client.cpp

#include <winsock2.h>
#include <stdio.h>
#include <iostream>
#include <cstring>#pragma comment(lib, "ws2_32.lib")int main()
{WORD sockVersion = MAKEWORD(2,2);WSADATA data;if(WSAStartup(sockVersion, &data) != 0){return 0;}SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if(sclient == INVALID_SOCKET){printf("Invalid socket!");return 0;}sockaddr_in serAddr;serAddr.sin_family = AF_INET;serAddr.sin_port = htons(6000);serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR){printf("connect error!");closesocket(sclient);return 0;}char sendData[255];while (true){std::cout << "Enter message: ";std::cin.getline(sendData, 255);if (strlen(sendData) == 0) {continue;}send(sclient, sendData, strlen(sendData), 0);printf("Sent: %s\n", sendData);}closesocket(sclient);WSACleanup();return 0;
}

4.在CLion建立客户端和服务端

修改CLion配置如下图

切换到此,点击运行即可进行通信

5. 运行效果

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

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

相关文章

go语言开发Prometheus Exporter(DM数据库)

一、介绍 源码步骤基于dameng_exporter源码讲解&#xff0c;看完本篇文章可以直接进行二次开发。 dameng exporter的开源地址&#xff1a;https://github.com/gy297879328/dameng_exporter&#xff08;可直接对接prometheusgrafana 提供表盘&#xff09; 开发一个exporter 其…

Linux中的三类读写函数

文件IO和标准IO的区别 遵循标准&#xff1a; 文件IO遵循POSIX标准&#xff0c;主要在类UNIX环境下使用。标准IO遵循ANSI标准&#xff0c;具有更好的可移植性&#xff0c;可以在不同的操作系统上重新编译后运行。可移植性&#xff1a; 文件IO的可移植性相对较差&#xff0c;因为…

基于大模型零代码1小时完成国标数据分级分类近义词库构建及思考

1. 任务背景及困难分析 因项目要求&#xff0c;需要对国家标准国民经济行业分类-GB/T 4754-2017【1】进行近义词库的构建&#xff0c;时间非常紧&#xff0c;只给了很短时间进行处理&#xff0c;目标是构建一份中等粒度的行业近义词库。 搁在以前&#xff0c;可能需要点时…

Linux 安装mysql-client-core-8.0

在Linux上安装mysql-client-core-8.0 安装流程 下面是安装mysql-client-core-8.0的步骤和相应的命令&#xff1a; 步骤1&#xff1a;更新系统软件源 我们首先需要更新系统的软件源&#xff0c;以确保我们能够获取到最新的软件包列表。使用以下命令更新软件源&#xff1a; …

Ansible——inventory 主机清单

1、inventory 含义 Inventory支持对主机进行分组&#xff0c;每个组内可以定义多个主机&#xff0c;每个主机都可以定义在任何一个或多个主机组内。 如果是名称类似的主机&#xff0c;可以使用列表的方式标识各个主机。 vim /etc/ansible/hosts [webservers] 192.168.20.11:222…

平凯星辰亮相 2024 中国国际金融展,发布银行交易明细查询白皮书

7 月 19 日至 21 日&#xff0c;备受瞩目的 2024 中国国际金融展&#xff08;以下简称金融展&#xff09;在北京国家会议中心隆重举办。作为中国乃至亚洲最大的金融科技展会&#xff0c;本届金融展以“数字金融引领未来&#xff0c;守正创新共筑金融新生态”为主题&#xff0c;…

C++_单例模式

目录 1、饿汉方式实现单例 2、懒汉方式实现单例 3、单例模式的总结 结语 前言&#xff1a; 在C中有许多设计模式&#xff0c;单例模式就是其中的一种&#xff0c;该模式主要针对类而设计&#xff0c;确保在一个进程下该类只能实例化出一个对象&#xff0c;因此名为单例。而…

temu数据分析怎么做,temu选品数据分析怎么做

在竞争激烈的电商市场中&#xff0c;数据分析已成为商家提升销售业绩、优化经营策略的重要工具。特别是对于Temu平台的卖家而言&#xff0c;掌握数据分析技巧&#xff0c;特别是选品数据分析&#xff0c;更是至关重要。本文将为您详细解析如何在Temu平台上进行数据分析&#xf…

Docker 安全及日志管理(包含SSL证书)

目录 一、Docker 存在的安全问题 二、Docker 架构缺陷与安全机制 三、Docker 安全基线标准 四、容器相关的常用安全配置方法 五、限制流量流向 六、镜像安全 七、DockerClient 端与 DockerDaemon 的通信安全 https的单向认证流程 https的双向认证流程 八、DockerClie…

Ubuntu 22.04.4 LTS (linux) GoAccess 分析 Nginx 日志

1 安装goaccess sudo apt-get update sudo apt-get install goaccess 2 控制台运行 goaccess -a -d -f /usr/local/openresty/nginx/logs/access.log -p /etc/goaccess/goaccess.conf #sudo vim /etc/goaccess/goaccess.conf time-format %H:%M:%S date-format %d/%b…

iOS ------ Block的相关问题

Block的定义 Block可以截获局部变量的匿名函数&#xff0c; 是将函数及其执行上下文封装起来的对象。 Block的实现 通过Clang将以下的OC代码转化为C代码 // Clang xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m//main.m #import <Foundation/Foundation.…

3.2、数据结构-数组、矩阵和广义表

数组结构 数组是定长线性表在维度上的扩展,即线性表中的元素又是一个线性表。N维数组是一种“同构”的数据结构,其每个数据元素类型相同、结构一致。 一个m行n列的数组表示如下: 其可以表示为行向量形式&#xff08;一行一行的数据&#xff09;或者列向量形式&#xff08;一…

Nginx 怎样处理请求的故障转移?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01; 文章目录 Nginx 怎样处理请求的故障转移&#xff1f;一、理解故障转移的重要性二、Nginx 中的故障检测机制三、Nginx 中的请求分配策略四、Nginx 中的故障转移实现方式五、…

Shell脚本编程(一)

目录 一、Shell命令行的书写规则 二、编写/修改权限及执行shell程序的步骤 1、编写简单Shell程序 2、建立可执行程序 3、执行Shell程序 4、实例 三、Shell程序中使用参数 1、位置参数 2、内部参数 3、实例一 4、实例二 一、Shell命令行的书写规则 在执行Shell命令时…

搭建本地私有知识问答系统:MaxKB + Ollama + Llama3 (wsl网络代理配置、MaxKB-API访问配置)

目录 搭建本地私有知识问答系统:MaxKB、Ollama 和 Llama3 实现指南引言MaxKB+Ollama+Llama 3 Start buildingMaxKB 简介:1.1、docker部署 MaxKB(方法一)1.1.1、启用wls或是开启Hyper使用 WSL 2 的优势1.1.2、安装docker1.1.3、docker部署 MaxKB (Max Knowledge Base)MaxKB …

便携式气象仪:科技赋能,让气象观测更智能

随着科技的快速发展&#xff0c;越来越多的领域受益于技术的进步。其中&#xff0c;气象观测领域也不例外。传统的气象观测设备虽然精确可靠&#xff0c;但往往体积庞大、携带不便&#xff0c;且需要专业人员进行操作和维护。而便携式气象仪的出现&#xff0c;则打破了这一局限…

在WPF中使用WebView2详解

Microsoft Edge WebView2 Microsoft Edge WebView2 控件允许在本机应用中嵌入 web 技术(HTML、CSS 以及 JavaScript)。 WebView2 控件使用 Microsoft Edge 作为绘制引擎&#xff0c;以在本机应用中显示 web 内容。 使用 WebView2 可以在本机应用的不同部分嵌入 Web 代码&…

Golang | Leetcode Golang题解之第284题窥视迭代器

题目&#xff1a; 题解&#xff1a; type PeekingIterator struct {iter *Iterator_hasNext bool_next int }func Constructor(iter *Iterator) *PeekingIterator {return &PeekingIterator{iter, iter.hasNext(), iter.next()} }func (it *PeekingIterator) hasNe…

学习记录day19——数据结构 查找算法

概念 在给定数据元素的某个值&#xff0c;在查找表中确定一个其关键字等于给定值的数据元素的操作&#xff0c;叫做查找 查找的分类 顺序查找:将待查找数据&#xff0c;进行全部遍历一遍&#xff0c;直到找到要查找的元素 折半查找:每次都去除一半的查找范围的查找方式&#x…

vue3响应式用法(高阶性能优化)

文章目录 前言&#xff1a;一、 shallowRef()二、 triggerRef()三、 customRef()四、 shallowReactive()五、 toRaw()六、 markRaw()七、 shallowReadonly()小结&#xff1a; 前言&#xff1a; 翻别人代码时&#xff0c;总结发现极大部分使用vue3的人只会用ref和reactive处理响…