C++网络编程——socket

在服务器中,需要建立一个socket套接字才能对外提供一个网络通信接口,在Linux系统中套接字仅是一个文件描述符,也就是一个int类型的值

socket概念

socket 的原意是“插座”,在计算机通信领域,socket 被翻译为“套接字”,它是计算机之间进行通信的一种约定或一种方式。通过 socket 这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据。

我们把插头插到插座上就能从电网上获得电力供应,同样为了与远程计算机进行数据传输,需要连接到因特网,而socket就是用来连接到因特网的工具

UNIX/Linux下的socket

在UNIX/Linux下,一切都是文件

为了表示和区分已经打开的文件,UNIX/Linux 会给每个文件分配一个 ID,这个 ID 就是一个整数,被称为文件描述符(File Descriptor)。例如:

  • 通常用 0 来表示标准输入文件(stdin),它对应的硬件设备就是键盘;

  • 通常用 1 来表示标准输出文件(stdout),它对应的硬件设备就是显示器。

UNIX/Linux 程序在执行任何形式的 I/O 操作时,都是在读取或者写入一个文件描述符。一个文件描述符只是一个和打开的文件相关联的整数,它的背后可能是一个硬盘上的普通文件、FIFO、管道、终端、键盘、显示器,甚至是一个网络连接。

请注意,网络连接也是一个文件,它也有文件描述符

Linux下socket使用

创建

#include<sys/socket.h>
int sockfd = socket(AF_INET,SOCK_STREAM,0);
  • 创建socket的API中第一个参数是IP地址类型,AF_INET表示使用IPv4,如果使用IPv6请使用AF_INET6,另外AF_UNIX则是Unix域套接字,即本地套接字

  • 第二个是参数为数据传输方式,SOCK_STREAM表示流格式、面向连接,多用于TCP。SOCK_DGRAM表示数据报格式、无连接,多用于UDP,至于TCP为什么为流格式,UDP为什么为面向报文,在专栏计算机网络部分为有详细解释。

  • 第三个参数:协议,0表示根据前面的两个参数自动推导协议类型。设置为IPPROTO_TCP和IPPTOTO_UDP,分别表示TCP和UDP。

sockadd_in结构体

对于客户端,服务器存在的唯一标识是一个IP地址和端口,这时候我们需要将这个套接字绑定到一个IP地址和端口上。首先创建一个sockaddr_in结构体

#include <arpa/inet.h>  //这个头文件包含了<netinet/in.h>,不用再次包含了
#include<string.h> //包含了bzero,如果是c使用string.h如果是C++使用cstring.h
struct sockaddr_in serv_addr;
bzero(&serv_addr, sizeof(serv_addr));

创建完后用bzero初始化这个结构体

sockaddr_in结构体内容如下:

struct sockaddr_in {sa_family_t sin_family;  // 地址族,通常设置为 AF_INETin_port_t sin_port;      // 端口号,网络字节序struct in_addr sin_addr; // IPv4 地址
};

其中IPV4地址结构体如下:

struct in_addr {in_addr_t s_addr; // 32位的 IPv4 地址,采用网络字节序
};

另外如果是在IPV6或者UNIX下本地套接字的话,要使用另外的结构体

  • IPV6:

struct sockaddr_in6 {sa_family_t     sin6_family;  // 地址族,通常设置为 AF_INET6in_port_t       sin6_port;    // 端口号,网络字节序uint32_t        sin6_flowinfo;// 流信息struct in6_addr sin6_addr;    // IPv6 地址uint32_t        sin6_scope_id;// 作用域ID
};
​
struct in6_addr {unsigned char   s6_addr[16]; // 128位的 IPv6 地址
};
  • UNIX:

struct sockaddr_un {sa_family_t sun_family; // 地址族,通常设置为 AF_UNIXchar        sun_path[108]; // Unix socket 的路径名
};

通用的sockaddr结构体

struct sockaddr {sa_family_t sa_family;  // 地址族char        sa_data[14]; // 地址信息
};
  1. sa_family

    • 表示地址族,通常取值为 AF_INETAF_INET6AF_UNIX 等。

    • 用于确定后续的地址信息如何解释。

  2. sa_data

    • 一个14字节的地址信息数组。

    • 具体的地址信息格式取决于地址族。

在初始化IPV4的结构体后,就要对其设置地址族,IP地址和端口

serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr.sin_port = htons(8888);

绑定

然后将socket地址与文件描述符绑定:

bind(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr));

为什么定义的时候使用专用socket地址,而绑定的时候转换为通用socket地址(sockaddr),这些内容在游双《Linux高性能服务器编程》第五章第一节:socket地址API中有详细讨论,我这里也进行一部分的引用加以说明

“通用socket地址结构体显然很不好用,比如设置与获取 IP地址和端口号就需要执行烦琐的位操作。所以Linux为各个协议族提 供了专门的socket地址结构体,同时所有专用socket地址类型的变量在实际使 用时都需要转化为通用socket地址类型sockaddr(强制转换即可),因 为所有socket编程接口使用的地址参数的类型都是sockaddr。”

inet_addr是将char类型字符串转变为网络字节序

#include <sys/socket.h>
​
#include <netinet/in.h>
​
#include <arpa/inet.h>
​
in_addr_t inet_addr(const char *cp); //将char类型字符串转变为网络字节序
​
char *inet_ntoa(struct in_addr in);  //将网络字节序转换为char类型

不过现在用这些比较少,

#include <arpa/inet.h>int inet_pton(int af, const char *src, void *dst);const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);//af参数指明IP地址族,可以是AF_INET(IPv4)或AF_INET6(IPv6)。//src参数是指向二进制IP地址的指针。//dst是存储转换后的文本IP地址的缓冲区。//size参数指明dst缓冲区的大小。//该函数返回一个指向dst的指针,如果失败则返回NULL并设置errno。int inet_pton(int af, const char *src, void *dst);//af参数指明IP地址族,可以是AF_INET(IPv4)或AF_INET6(IPv6)。//src参数是指向文本IP地址的指针。//dst是存储转换后的二进制IP地址的缓冲区。//该函数返回值://如果转换成功,返回1。//如果src参数不是有效的IP地址字符串,返回0。//如果出错,返回-1并设置errno。

例如:

#include<stdio.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<arpa/inet.h>
​
int main(){char buf[] = "192.168.1.2"; //低字节为2,高字节为192unsigned int name = 0;inet_pton(AF_INET,buf,&name);  //将点分十进制转换为网络字节序,大端存储,发送时用的多printf("name = %d\n",name); //0x0201a8c0unsigned char* p = (unsigned char*) &name;printf("%d,%d,%d,%d\n",*p,*(p+1),*(p+2),*(p+3)); //大端存储char ip[16] = "";inet_ntop(AF_INET,&name,ip,16); //将网络字节序转换为点分十进制  ,接收时用的多printf("%s",ip);
}

打印结果为:

name = 33663168 
192,168,1,2
192.168.1.2

监听

使用listen函数监听这个socket端口,这个函数的第二个参数是listen函数的最大监听队列长度,系统建议的最大值SOMAXCONN被定义为128。

listen(sockfd, SOMAXCONN);

要接受一个客户端连接,需要使用accept函数。对于每一个客户端,我们在接受连接时也需要保存客户端的socket地址信息,于是有以下代码:

struct sockaddr_in clnt_addr;
socklen_t clnt_addr_len = sizeof(clnt_addr);
bzero(&clnt_addr, sizeof(clnt_addr));
int clnt_sockfd = accept(sockfd, (sockaddr*)&clnt_addr, &clnt_addr_len);
printf("new client fd %d! IP: %s Port: %d\n", clnt_sockfd, inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port));

要注意和acceptbind的第三个参数有一点区别,对于bind只需要传入serv_addr的大小即可,而accept需要写入客户端socket长度,所以需要定义一个类型为socklen_t的变量,并传入这个变量的地址。另外,accept函数会阻塞当前程序,直到有一个客户端socket被接受后程序才会往下运行。

现在,客户端已经可以通过IP地址和端口号连接到这个socket端口了,让我们写一个测试客户端连接试试:

int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in serv_addr;
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr.sin_port = htons(8888);
connect(sockfd, (sockaddr*)&serv_addr, sizeof(serv_addr));  

代码和服务器代码几乎一样:创建一个socket文件描述符,与一个IP地址和端口绑定,最后并不是监听这个端口,而是使用connect函数尝试连接这个服务器。

运行编译出来的./server和./client可以看到服务器接收到了客户端的连接请求,并成功连接

new client fd 3! IP: 127.0.0.1 Port: 53505

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

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

相关文章

OpenStack创建云主机——超级详细步骤

四、创建云主机 一台云主机成功创建或启动需要依赖OpenStack中的各种虚拟资源&#xff0c;如CPU、内存、硬盘等。如果需要云主机丽娜姐外部网络&#xff0c;还需要网络、路由器等资源。如果需要外部网络访问云主机&#xff0c;那么还需要配置浮动IP。因此&#xff0c;在创建云主…

开源监控工具monit安装部署

Monit 简介 Monit是一个轻量级(500KB)跨平台的用来监控Unix/linux系统的开源工具。部署简单&#xff0c;并且不依赖任何第三方程序、插件或者库。 Monit可以监控服务器进程、文件、文件系统、网络状态&#xff08;HTTP/SMTP等协议&#xff09;、远程主机、服务器资源变化等等。…

【全开源】旅游系统源码(Uniapp+FastAdmin+ThinkPHP)

一款基于UniappFastAdminThinkPHP开发的旅游系统&#xff0c;包含消费者端&#xff08;手机端&#xff09;、机构工作人员&#xff08;手机端&#xff09;、机构端&#xff08;PC&#xff09;、平台管理端&#xff08;PC&#xff09;。机构可以发布旅游线路、景点项目&#xff…

React18 apexcharts数据可视化之甜甜圈图

03 甜甜圈图 apexcharts数据可视化之甜甜圈图。 有完整配套的Python后端代码。 本教程主要会介绍如下图形绘制方式&#xff1a; 基本甜甜圈图个性图案的甜甜圈图渐变色的甜甜圈图 面包圈 import ApexChart from react-apexcharts;export function DonutUpdate() {// 数据…

Linux——多线程(一)

一、线程的概念 1.1线程概念 教材中的概念&#xff1a; (有问题?) 线程是进程内部的一个执行分支&#xff0c;线程是CPU调度的基本单位 之前我们讲的进程&#xff1a; 加载到内存中的程序&#x…

栈的特性及代码实现(C语言)

目录 栈的定义 栈的结构选取 链式储存结构和顺序栈储存结构的差异 栈的代码实现 "stack.h" "stack.c" 总结 栈的定义 栈&#xff1a;栈是限定仅在表尾进行插入和删除操作的线性表。 我们把运行插入的和删除的一段叫做栈顶&#xff08;TOP&#xff…

【JVM】一次JVM内存泄露分析处理

一次内存泄露分析 背景情况 编写了一个大数据基础组件的可用性监控程序&#xff0c;采用Bootstrap监测端口的方式&#xff0c;使得方法常驻&#xff08;main线程常驻&#xff09;&#xff0c;通过一个调度线程ScheduledThreadPoolExecutor&#xff0c;定时的调动监测任务。 …

adb获取包名和界面名

adb获取包名和界面名 mac adb shell dumpsys window windows | grep mFocusedApp windows adb shell dumpsys window windows | findstr mFocusedApp 这个是在当前手机打开哪个界面获取的就是哪个界面的包名与界面 注意第一次连接时会有提示&#xff0c;需要连接两次才可以 …

【AI算法岗面试八股面经【超全整理】——机器学习】

AI算法岗面试八股面经【超全整理】 概率论信息论机器学习深度学习CVNLP 目录 1、回归损失函数2、分类损失函数3、误差&#xff08;Error&#xff09;、偏差&#xff08;Bias&#xff09;、方差&#xff08;Variance&#xff09;4、PCA&#xff08;Principle Component Analysi…

四川汇聚荣聚荣科技有限公司好不好?

在当今科技飞速发展的时代&#xff0c;企业要想在激烈的市场竞争中脱颖而出&#xff0c;必须具备强大的技术实力和良好的市场口碑。那么&#xff0c;作为一家专注于科技创新的公司&#xff0c;四川汇聚荣聚荣科技有限公司究竟如何呢?接下来&#xff0c;我们将从四个方面进行详…

扔掉 MacBook,挑战带OrangePi出差!

背景 由于工作需要&#xff0c;博主经常会到各大企业的自建机房中私有化部署公司的软件产品。 在某些企业自建机房中&#xff0c;有时给到全新的机器&#xff0c;没有基础环境&#xff0c;甚至有的还无法互联网&#xff0c;而且因为近几年CentOS的停止更新&#xff0c;服务器…

【Linux】Linux的权限_2 + Linux环境基础开发工具_1

文章目录 三、权限3. Linux权限管理修改文件的拥有者和所属组 4. 文件的类型5. 权限掩码 四、Linux环境基础开发工具1. yumyum 工具的使用 未完待续 三、权限 3. Linux权限管理 修改文件的拥有者和所属组 在上一节我们讲到如何更改文件的访问权限&#xff0c;那我们需要更改…

光伏智慧化运营解决方案的应用和价值

在社会对新能源需求的不断扩大&#xff0c;光伏已经成为了可再生能源的重要组成部分&#xff0c;随着光伏电站数量和规模的不断扩大&#xff0c;相关企业和用户都就开始关注如何能够高效精准的进行电站管理&#xff0c;对此&#xff0c;鹧鸪云提出了光伏智慧化运营解决方案&…

【官方指南】3ds Max中纹理贴图问题及正确解决方案

在使用3ds Max进行设计和制作时&#xff0c;纹理贴图是一个非常重要的环节。然而&#xff0c;许多用户在使用过程中常会遇到各种纹理贴图问题。为此&#xff0c;Autodesk官方提供了一些有效的解决方案&#xff0c;可以解决90%的纹理贴图难题。这里小编都帮大家整理好了&#xf…

简化跨网文件传输摆渡过程,降低IT人员工作量

在当今数字化时代&#xff0c;IT企业面临着日益增长的数据交换需求。随着网络安全威胁的不断演变&#xff0c;网关隔离成为了保护企业内部网络不受外部威胁的重要手段。然而&#xff0c;隔离的同时&#xff0c;企业也需要在不同网络间安全、高效地传输文件&#xff0c;这就催生…

线性回归计算举例

使用正规方程计算&#xff08;一元线性回归&#xff09; import numpy as np import matplotlib.pyplot as plt # 转化成矩阵 X np.linspace(0, 10, num 30).reshape(-1, 1) # 斜率和截距&#xff0c;随机生成 w np.random.randint(1, 5, size 1) b np.random.randint(1,…

Qt项目使用pato mqtt C

一,下载pato mqtt C 源码 git 地址:https://github.com/eclipse/paho.mqtt.c.git git 地址可能下载不下来,提供我的gitee地址 gitee地址:https://gitee.com/chaojidahuaidan2021/paho.mqtt.c.git 二,编译共享库 clone下来后,将项目导入到Qt工程中,此时这是一个cmke工程…

三十一、openlayers官网示例Draw Features解析——在地图上自定义绘制点、线、多边形、圆形并获取图形数据

官网demo地址&#xff1a; Draw Features 先初始化地图&#xff0c;准备一个空的矢量图层&#xff0c;用于显示绘制的图形。 initLayers() {const raster new TileLayer({source: new XYZ({url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/…

Kubernetes和Docker对不同OS和CPU架构的适配关系

Docker Docker官网对操作系统和CPU架构的适配关系图 对于其他发行版本&#xff0c;Docker官方表示没有测试或验证在相应衍生发行版本上的安装&#xff0c;并建议针对例如Debian、Ubuntu等衍生发行版本上使用官方的对应版本。 Kubernetes X86-64 ARM64 Debian系 √ √ Re…

贪心算法[1]

首先用最最最经典的部分背包问题来引入贪心的思想。 由题意可知我们需要挑选出价值最大的物品放入背包&#xff0c;价值即单位价值。 我们需要计算出每一堆金币中单位价值。金币的属性涉及两个特征&#xff0c;重量和价值。 所以我们使用结构体。 上代码。 #include <i…