Linux之socket编程(上)

embedded/2025/1/23 10:31:47/

目录

理解IP和端口号

 socket编程接口

 简单UDP网络小程序实现


本期我们将开始学习Linux计算机网络的相关知识。

理解IP和端口号

IP:一个IP唯一标识一个网络中的主机。

端口号:唯一标识一个主机中的一个进程。

IP+端口号我们也称作套接字

所以我们可以得出一个结论,IP+端口号可以唯一标识一个计算机中的一个进程。 

在学习Linux操作系统的时候我们也学习过进程的概念,在操作系统中我们使用pid来唯一标识计算机中的一个进程。那么套接字和进程pid冲突吗?

其实也不冲突,就如学生的身份证号和学生在学校的学号一样,都可以唯一标识学生的身份。那为什么在学校不用学生的身份证号作为学生的学号呢?其实这是为了解耦,如果真的使用身份证号作为学生的学号,那么万一有一天身份证号报废了,学生在学校的学号也就报废了。所以为了防止类似的情况出现,我们使用了学号,实现了学校与外界环境的解耦。在计算机网络中使用套接字也是类似的原因。

 socket编程接口

// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)

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

// 绑定端口号 (TCP/UDP, 服务器)

int bind(int socket, const struct sockaddr *address, socklen_t address_len);

// 开始监听socket (TCP, 服务器)

int listen(int socket, int backlog);

// 接收请求 (TCP, 服务器)

int accept(int socket, struct sockaddr* address, socklen_t* address_len);

// 建立连接 (TCP, 客户端)

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

计算机网络通信中,socket通信方式有很多种,网络套接和域间套接,但是不难发现,在socket编程中只有唯一的接口。那么针对不同的socket通信方式怎么样保证只用上述唯一的接口就能实现通信呢?

回答这个问题之前,我们先来了解一下,不同通信方式所对应的数据结构。有三种数据结构,准确来说有两种数据结构。图示如下。

struct sockaddr_in 对应网络套接,struct sockaddr_un对应域间套接。这两个数据结构可以强转成struct sockaddr通用结构,进而使得多种socket通信方式使用同一套socket接口。 

 简单UDP网络小程序实现

题设:使用socket相关api接口,实现client客户端进程发送任意消息,sever服务器端进程接收到“你好之后”,给client客户端进程返回“hello”功能的程序。

客户端代码如下。

udp_client.cc

#include <iostream>
#include <sys/types.h>
#include <cerrno>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>int main(int argc, char *argv[])
{// 客户端// 1.创建套接字,打开网络文件int sock = socket(AF_INET, SOCK_DGRAM, 0);if (sock < 0){std::cout << "socket create error" << errno << std::endl;return 1;}// 客户端需要绑定ip和端口吗// 不需要,因为客户端是向服务器端发送数据的,所以不需要,ip和端口号,// 发送数据时,操作系统自动绑定//2.使用服务while (1){// 给谁发struct sockaddr_in sever;sever.sin_family = AF_INET;sever.sin_port = htons(atoi(argv[2]));sever.sin_addr.s_addr = inet_addr(argv[1]);// 向服务器发送数据std::string message;std::cout<<"请输入# ";std::cin >> message;sendto(sock, message.c_str(), message.size(), 0, (struct sockaddr *)&sever, sizeof(sever));// 获取从服务器中返回的数据struct sockaddr_in tmp;#define NUM 1024char buffer[NUM];socklen_t len = sizeof(tmp);recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&tmp, &len);std::cout << "sever返回的数据: " << buffer << std::endl;}return 0;
}

1. 客户端进程先创建并打开一个套接字文件。客户端不用去绑定IP和端口号,因为客户端是向服务器端发送数据的,所以在发送数据时操作系统会自动为客户端进程绑定IP和端口号。

2.客户端进程获取服务,接收到了服务器端进程返回的数据。

服务器端代码如下。

udp_sever.cc

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <cerrno>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<string>const uint16_t port = 8080;
int main()
{// 1.创建socket,即打开一个文件int sock = socket(AF_INET, SOCK_DGRAM, 0);if (sock < 0){std::cout << "socket create erro" << errno << std::endl;return 1;}// 2.绑定IP和端口号struct sockaddr_in local;// 当前socket通信方式为网络套接。local.sin_family = AF_INET;local.sin_port = htons(port);// 绑定IP,需要将点分十进制IP转为32位整数IP地址,与此同时还要考虑大小端存储,// 所以使用inet_addr()接口即可// 但一般在服务器端,我们一般不显式绑定IP,因为在服务器端,可以认为一个服务器// 可以有多个IP,所以服务器可以接收所有向该主机IP传递的数据,而不是只接收// 给定的一个IP收到的数据local.sin_addr.s_addr = INADDR_ANY; // 默认接收向该主机所有IP传递的数据if (bind(sock, (const sockaddr *)&local, sizeof(local)) < 0){std::cout << "bind err" << errno << std::endl;return 2;}//提供服务#define NUM 1024char buffer[NUM];while(1){//1.接收从客户端发送的数据struct sockaddr_in peer;socklen_t len=sizeof(peer);recvfrom(sock,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);std::cout <<"#client发送的数据: "<<buffer << std::endl;//2.获取到数据之后,向客户端发送返回的数据std::string message="hello";sendto(sock,message.c_str(),message.size(),0,(struct sockaddr*)&peer,len);}return 0;
}

1.服务器进程创建并打开一个套接字文件。

2.服务器端进程需要绑定IP和端口号,因为服务器端是接收数据的,所以必须绑定IP和端口号,只有这样,客户端进程才知道往哪个服务器进程发送数据。

3.创建服务,接收客户端进程发送的数据,并向客户端进程发送返回的数据。

运行结果如下。

运行结果符合预期。

以上便是本期的所有内容。

本期内容到此结束^_^ 


http://www.ppmy.cn/embedded/156279.html

相关文章

通过frm和ibd文件恢复mysql数据

1.提取所有的文件名并查找出以frm结尾的 dir /t /b >1.txt 2.要准备的软件 1.mysql-utilities-1.6.5-winx64.msi 2.vcredist_x64.exe(c 2013) 3.利用frm生成sql文件 mysqlfrm --serverroot:123456localhost:3306 --port3308 D:\phpstudy_pro\Extensions\MySQL5.7.26\da…

PyQt5 超详细入门级教程上篇

PyQt5 超详细入门级教程 上篇&#xff1a;1-3部分&#xff1a;PyQt5基础与常用控件 第1部分&#xff1a;初识 PyQt5 和安装 1.1 什么是 PyQt5&#xff1f; PyQt5 是 Python 的图形用户界面 (GUI) 框架&#xff0c;它基于强大的 Qt 库。Qt 是一个跨平台的 C 框架&#xff0c;用…

三层软电话技术

随着信息技术的飞速发展&#xff0c;企业通讯方式也在不断演进。三层软电话技术作为一种先进的通讯解决方案&#xff0c;正在被越来越多的企业所采纳。本文将全面解析三层软电话的定义、应用场景、工作原理、优势以及劣势&#xff0c;并对其进行拓展探讨。 一、三层软电话 三层…

Linux网络 序列化与反序列化

概念 序列化&#xff08;Serialization&#xff09;是将对象的状态信息转换为可以存储或传输的形式的过程。以下是关于序列化与反序列化的介绍&#xff1a; 序列化&#xff1a;将对象的状态信息转换为可以存储或传输的格式&#xff0c;通常是字节序列或文本格式。反序列化&am…

C++之初识模版

目录 1.关于模版的介绍 2.函数模版 2.1函数模板概念 2.2函数模板格式 2.3 函数模板的原理 2.4 函数模板的实例化 2.5模板参数的匹配原则 3.类模版 3.1类模板的定义格式 3.2 类模板的实例化 1.关于模版的介绍 C中的模板是一种通用编程工具&#xff0c;它允许程序员编…

数据结构——堆(介绍,堆的基本操作、堆排序)

我是一个计算机专业研0的学生卡蒙Camel&#x1f42b;&#x1f42b;&#x1f42b;&#xff08;刚保研&#xff09; 记录每天学习过程&#xff08;主要学习Java、python、人工智能&#xff09;&#xff0c;总结知识点&#xff08;内容来自&#xff1a;自我总结网上借鉴&#xff0…

C++:将字符数组rkpryyrag,每个字母转换为其前面第13个字母后输出,如果超过a则从z再继续接着数。例如:b前面第1个字母是a。a前面第3个字母是x。

代码如下&#xff1a; #include <iostream> #include <string> using namespace std;int main(){string str "rkpryyrag";for (int i 0; i < str.length(); i){if (str[i] > a && str[i] < z){if (str[i] - a < 13){cout <<…

ASP.NET Blazor部署方式有哪些?

今天我们来说说Blazor的三种部署方式&#xff0c;如果大家还不了解Blazor&#xff0c;那么我先简单介绍下Blazor Blazor 是一种 .NET 前端 Web 框架&#xff0c;在单个编程模型中同时支持服务器端呈现和客户端交互性&#xff1a; ● 使用 C# 创建丰富的交互式 UI。 ● 共享使用…