Linux学习笔记(Socket)

Linux-Socket

  • 1、基础知识
  • 2、服务端
  • 3、客户端
  • 4、读写操作
    • 4.1、读写函数
    • 4.2、阻塞IO和非阻塞IO
  • 5、例程

1、基础知识

socket用于计算机之间的网络通信,无论是构建服务器还是客户端,我们仅需要三个信息,服务器的ip地址,对应进程的端口号,通信协议
拿到ip地址,便自然知道其ip种类且同时知道该服务器的位置,拿到端口号便知道具体和哪个程序对接。一般而言我们使用ipv4的地址格式,端口号也一般设置得大一些,以防止和服务器原本的应用程序冲突。通信协议则分为流式和报式两个种,它们的代表协议分别是TCP和UDP。
总而言之,只要得到这些信息,服务器就能构建其服务程序,客户端也能准确的找到对应的服务程序。
而socket这个名字,也生动的表达的这样一层意思,把服务器看成一个插排,客户端看成各类用电器,一个插排可以给N个设备供电。
在这里插入图片描述

2、服务端

第一步,创建一个套接字,并拿到一个文件描述符,以便捷的表示这个套接字。
第二步,构建一个结构体,让这个结构体绑定各种信息(ip地址,端口号,通信协议)。
第三步,开始准备接受客户端的连接请求。
第四步,处理客户端的连接请求(验证ip地址和端口号是否对上),并为客户端分配独一无二的文件描述符。
最后,根据需要进行读写操作。
下面的例程,每一步具体代码怎么写我大致有标注一下。

//设置ip和端口号
std::string server_ip_address = "xxx.xxx.xxx.xxx";
int server_port = 8888;//step 1
int fd = socket(AF_INET, SOCK_STREAM, 0);//step2
sockaddr_in addr;		//定义一个结构体
addr.sin_family = AF_INET;		//指定ip地址格式
addr.sin_port = htons(server_port);		//设置端口
inet_pton(AF_INET, server_ip_address.c_str(),  &addr.sin_addr.s_addr);	//设置ip地址
bind(fd, (struct sockaddr*)&addr, sizeof(addr));	//绑定信息//step3
listen(fd, 128);//step4
sockaddr_in client_addr;		//定义一个结构体接受客户端信息
socklen_t clilen = sizeof(client_addr);
int cfd = accept(sfd, (struct sockaddr*)&client_addr, &clilen);		//比对信息是否匹配

如果想要具体了解各个函数的参数的意义,直接copy之后搜索即可。
有几个点可以注意一下
1、写代码的时候数据的存储方式是小端存储,即主机字节序。譬如这一句:

int server_port = 8888;

它在内存当中就是主机存储。但是用于网络通讯的时候,又是大端存储(又称网络字节序)。所以需要转化一下,一般用到的函数有:htons, htonl, ntohs, ntohl.
意思也很直白,以htons为例,htons即host to network short。host意为主机字节序,network意为网络字节序,short指的是要转化的字节数,short指的是2个字节,long指的是4个字节(和long int对应的字节数不太一样)。
2、listen(fd, 128);这里的128并不是指最多只能接受128个客户端,而是在listen那一瞬间最多只能处理128个,可以多执行几次listen的。
3、在字符串传输的时候不需要考虑字节序的问题。因为一个字符本身就占一个字节,不存在字节内部被打乱的可能。也就是说,所谓字节序的问题是存在局部的,而不存在于整体中。
举个例子,9这个整数,占四个字节,转化成字节流是长这样的。
小端存储(主机字节序):9:0x00 0x00 0x00 0x09
大端存储(网络字节序):9:0x09 0x00 0x00 0x00(其实比对一下,就可以get到为啥传输的时候变成大端的了)
如果是3和9两个数字分别发过去,则不会,也不可以影响3和9的发送顺序。所以对于字符串"abcd",它的发送顺序就是"a" “b” “c” “d”。又因为它们本身就只占一个字节,自然不会被存储方式干扰。
但是如果一个汉字,它由于占多个字节,倒有可能受到字节序的影响。
总的来说,字节序的问题只出现在一个整体被拆分成N个字节,然后传输之后重组才可能出现。
4、如果cfd不为-1则表示正确和客户端建立连接,可以进行读写操作了。具体代码之后再说。

3、客户端

从客户端的角度来说,其主要任务就是拿到服务器的ip地址,端口号,然后主要去和客户端建立起连接。譬如插线要去匹配插座一样。核心步骤和构建服务器的步骤大同小异,大概如下:
第一步,创建一个套接字,并拿到一个文件描述符,以便捷的表示这个套接字。
第二步,构建一个结构体,让这个结构体绑定服务器的各种信息ip地址,端口号,通信协议)。
第三步,利用以上这些信息尝试去连接服务器,如果构建成功则返回的整形变量是正值。
第四步,根据任务需要进行读写操作。

//step 1:
int fd = socket(AF_INET, SOCK_STREAM, 0);//step 2:
sockaddr_in saddr;
addr.sin_family = AF_INET;
addr.sin_port = htons(server_port);
inet_pton(AF_INET, server_ip_address.c_str(),  &addr.sin_addr.s_addr);//step 3:
do{		ret = connect(sfd, (struct sockaddr*)&saddr, sizeof(saddr));	//connect是一个非阻塞函数,所以需要用while不断尝试去建立连接std::cout << "try to connect server...\n";sleep(1);
}while(ret == -1);

4、读写操作

4.1、读写函数

读用的是write

ssize_t write(int fd, const void *buf, size_t count);
  • fd是文件描述符。
  • buf被写内容的地址。
  • count自然是被写内容的字节数。
  • 返回值:如果写入成功,则返回写入的字节数目。如果失败,返回-1;如果正常写入,但没写入任何东西,则返回0。

读操作用的是read函数

ssize_t read(int fd, void *buf, size_t count);
  • fd:文件描述符。
  • buf:指向读取的内容的指针 。
  • count:要读取的字节数 。
  • 返回值:如果读取成功,则返回读取的字节数目。如果失败,返回-1;如果正常读取,但没读取到东西,返回0。

其实这里write和read和Linux文件IO操作中的read和write函数是一样的,包括close操作也是。可以看我之前写的文章。
链接: Linux学习笔记之四(文件IO、目录IO)

4.2、阻塞IO和非阻塞IO

其实无论是调用write函数还是read函数,都是在内核空间中的缓存区进行操作。流程大概是,通过write函数把数据写到内核空间的写缓存区,然后内核自动通过一些协议把数据传输到读缓存区,然后read函数才能从读缓存区把数据给读出来。
在这里插入图片描述
但是这个读写操作分为阻塞式读写和非阻塞式读写,专业术语叫阻塞IO和非阻塞IO。默认情况下是采用阻塞式IO,在阻值式模式下,write操作如果发现写缓存区已经满了,则会一直在那里等待,直到有多余空间可以写入;对于read操作来说,则是如果发现读缓存区没有数据,则一直阻塞等待,直到有数据出现。
而非阻塞式刚好相反,以read为例,如果发现读缓存区中没有数据,则返回-1,然后继续执行其它任务。
非阻塞可以通过相关函数来设置,自行上网查即可。下面讲讲它们的优缺点。

  • 阻塞式IO
    • 优点:操作和逻辑都比较简单,确保write和read能正确执行才继续执行其它任务。
    • 缺点:浪费线程时间,有可以阻塞的时间过长而影响其它任务的执行。
  • 非阻塞式IO
    • 优点:可以及时的去执行其它任务,提高线程的利用率。
    • 缺点:可以导致读写数据不及时。

总的两说,两者各有优劣。但也有一些方法可以取长补短,比如select,epoll,poll等。暂且不谈了。

5、例程

服务器例程,我将读写分为两个线程来写。

#include <iostream>
#include <thread>
#include <mutex>
#include <string>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>std::string server_ip_address = "192.168.52.130";
int server_port = 8888;
int exit_flag = 0;
std::mutex mu;int ServerInit()
{//create a socket descriptionint fd = socket(AF_INET, SOCK_STREAM, 0);sockaddr_in addr;//get ip typeaddr.sin_family = AF_INET;//get host portaddr.sin_port = htons(server_port);//get ip iddressinet_pton(AF_INET, server_ip_address.c_str(),  &addr.sin_addr.s_addr);//link above information to socketbind(fd, (struct sockaddr*)&addr, sizeof(addr));return fd;
}void SendThread(int cfd)
{std::string meg;while(true){std::getline(std::cin, meg);if(meg == "exit"){write(cfd, meg.c_str(), meg.length());mu.lock();exit_flag = 1;mu.unlock();break;} write(cfd, meg.c_str(), meg.length());}
}void ReceThread(int cfd)
{char buf[1024];while(exit_flag == 0){//set buff to zeromemset(buf, 0, sizeof(buf));int len = read(cfd, buf, sizeof(buf));if(len > 0)     std::cout << " receive from client is: " << buf << std::endl;}
}int main()
{//sfd: server file descriptionint sfd = ServerInit();//beign to wait for client, block.listen(sfd, 128);sockaddr_in client_addr;socklen_t clilen = sizeof(client_addr);//receive the information from client, cfd: client file desriptionint cfd = accept(sfd, (struct sockaddr*)&client_addr, &clilen);if(cfd != -1){std::thread send_thread(SendThread, cfd);std::thread rece_thread(ReceThread, cfd);send_thread.join();rece_thread.join();}close(cfd);close(sfd);return 0;
}

客户端例程

#include <iostream>
#include <stdio.h>
#include <string>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>std::string server_ip_address = "192.168.52.130";
int server_port = 8888;int ClientInit(sockaddr_in& addr)
{//create a socket descriptionint fd = socket(AF_INET, SOCK_STREAM, 0);//get ip typeaddr.sin_family = AF_INET;//get host portaddr.sin_port = htons(server_port);//get ip iddressinet_pton(AF_INET, server_ip_address.c_str(),  &addr.sin_addr.s_addr);return fd;
}int main()
{//sfd: server file description, saddr: server addresssockaddr_in saddr;int sfd = ClientInit(saddr);int ret;do{ret = connect(sfd, (struct sockaddr*)&saddr, sizeof(saddr));std::cout << "try to connect server...\n";sleep(1);}while(ret == -1);std::cout << "connect server successfully!\n";while(1){static char buf[1024] = {0};static std::string str = "hello, i am client.";write(sfd, str.c_str(), str.size());int len  = read(sfd, buf, sizeof(buf));if(len > 0){std::cout << "client receive is: " << buf << std::endl;memset(buf, 0 , sizeof(buf));} else if(len == 0){std::cerr << "lose connection with server.\n";break;}}close(sfd);return 0;
}

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

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

相关文章

openlayers 热力图 天地图

openlayers 实现热力图 样式可调 在https://blog.csdn.net/qq_36287830/article/details/131844745?spm1001.2014.3001.5501基础上改进来的 关键代码 如果你有数据可以不使用for循环 var blurInput document.getElementById("blur");var rediusInput document.g…

PyQt5编写的一个简易图像处理软件

文章目录 1. 简介2. 准备工作3. 主界面设计4. 功能构建5. 总结 1. 简介 通过编写简易图像处理软件&#xff0c;你可以学习如何使用 PyQt5 构建用户界面&#xff0c;以及如何与用户交互。同时&#xff0c;你还可以学习图像处理技术&#xff0c;如图像读取、傅里叶变换、滤波、增…

【NR学习一】NR中的带宽、子载波间隔、PRB数量、FFT点数与采样率之间的关系

NR中的带宽、子载波间隔、PRB数量、FFT点数与采样率之间的运算关系 在5G NR&#xff08;New Radio&#xff09;系统设计中&#xff0c;带宽&#xff08;Bandwidth&#xff09;、子载波间隔&#xff08;Subcarrier Spacing, SCS&#xff09;、资源块&#xff08;Resource Block…

仓库管理流程详解(附作业流程图)

仓库管理流程在企业的日常运营中至关重要。它不仅是物资流转的核心环节&#xff0c;更关乎着企业的运营效率、成本控制和客户服务水平。一个高效、规范的仓库管理流程能够确保货物从入库到出库的各个环节有序进行&#xff0c;减少资源浪费和时间成本&#xff0c;同时帮助企业实…

泽攸科技无掩模光刻机:引领微纳制造新纪元

在当今科技迅猛发展的时代&#xff0c;微纳制造技术正变得越来越重要。泽攸科技作为这一领域的先行者&#xff0c;推出了其创新的无掩模光刻机&#xff0c;这一设备在微电子制造、微纳加工、MEMS、LED、生物芯片等多个高科技领域展现出了其独特的价值和广泛的应用前景。 技术革…

数据分析(二)——导入外部数据,导入Excel数据,CSV文件,txt文件,HTML网页,数据抽取,DataFrame对象的loc属性与iloc属性

一.导入外部数据 1.导入.xIs或.xIsx文件 pd.read_ excel(io,sheet_ name,header) 1.1常用参数说明 ●io:表示.xIs或.xIsx文件路径或类文件对象 ●sheet name:表示工作表&#xff0c;取值如下表所示 ●header:默认值为0&#xff0c;取第一行的值为列名&#xff0c;数据为除列…

手撸XXL-JOB(四)——远程调用定时任务

Java Socket网络编程 网络编程是Java编程中的重要组成部分&#xff0c;包括服务端和客户端两部分内容。Socket是Java网络编程的基本组件之一&#xff0c;用于在应用程序之间提供双向通信&#xff0c;Socket提供了一种标准的接口&#xff0c;允许应用程序通过网络发送和接收数据…

数据中台管理系统原型

数据中台是一个通用性的基础平台&#xff0c;适用于各类行业场景&#xff0c;数据中台包含多元数据汇聚、数据标准化、数据开发、数据共享、数据智能、数据资产管理等功能&#xff0c;助力企业数字化转型。 数据汇聚 数据汇聚是将不同系统、不同类型的多元源数据汇聚至目标数据…

20.接口自动化-Git

1、Git和SVN–版本控制系统 远程服务出问题后&#xff0c;可以先提交commit到本地仓库&#xff0c;之后再提交push远程仓库 git有clone Git环境组成部分 常用Git代码仓库服务-远程仓库 GitHub-服务器在国外&#xff0c;慢 GitLab-开源&#xff0c;可以在自己服务器搭建&…

真JAVA代码审计之XSS漏洞

Part1 漏洞案例demo&#xff1a; 没有java代码审计XSS漏洞拿赏金的案例。 所以将就看看demo吧 漏洞原理&#xff1a;关于XSS漏洞的漏洞原理核心其实没啥好说的&#xff0c;网上一查一大堆。 反射性XSS漏洞 <% page language"java" contentType"text/ht…

2. 感知机算法和简单 Python 实现

目录 1. 感知机介绍 1.1 背景 1.2 定义 1.2.1 权重 1.2.2 阈值 1.2.3 偏置 1.3 逻辑处理&#xff1a;与门、非门、或门 2. 感知机实现 2.1 与门的 Python 实现 2.2 非门的 Python 实现 2.3 或门的 Python 实现 1. 感知机介绍 1.1 背景 感知机1957年由 Rosenblatt 提…

【全开源】JAVA国际版多语言语聊大厅语音聊天APP系统源码

国际版多语言语聊大厅语音聊天APP系统&#xff1a;跨越语言的界限&#xff0c;连接世界的声音 在全球化日益加速的今天&#xff0c;语言不再是沟通的障碍。我们很高兴地宣布&#xff0c;全新的“国际版多语言语聊大厅语音聊天APP系统”已经正式上线&#xff0c;旨在为全球用户…

【千帆AppBuidler】零代码构建AI人工智能应用,全网都在喊话歌手谁能应战,一键AI制作歌手信息查询应用

欢迎来到《小5讲堂》 这是《千帆平台》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 背景创建应用平台地址随机生成快速创建应用头像应用名称应用描述…

【基于element ui的color选择器】基于element ui的color选择器

技术版本如下&#xff1a; vue 2.6.14 less 3.13.1 element-ui 2.15.6 less-loader 5.0.0需求&#xff1a; 支持RGB、HEX编码、支持吸管吸取颜色、颜色选择器、颜色模板、透明度、色板、线性渐变颜色 效果图&#xff1a; 1.引入选择器的color-all文件 <template><…

[vue] nvm

nvm ls // 看安装的所有node.js的版本nvm list available // 查显示可以安装的所有node.js的版本可以在可选列表里。选择任意版本安装&#xff0c;比如安装16.15.0 执行&#xff1a; nvm install 16.15.0安装好了之后。可以执行&#xff1a; …

鸿蒙内核源码分析 (内核启动篇) | 从汇编到 main ()

这应该是系列篇最难写的一篇&#xff0c;全是汇编代码&#xff0c;需大量的底层知识&#xff0c;涉及协处理器&#xff0c;内核镜像重定位&#xff0c;创建内核映射表&#xff0c;初始化 CPU 模式栈&#xff0c;热启动&#xff0c;到最后熟悉的 main() 。 内核入口 在链接文件…

FreeRTOS开发一、FreeRTOS移植

1、FreeRTOS 源码下载 两个下载链接&#xff0c; 一个是官网&#xff1a;http://www.freertos.org/&#xff0c; 另外一个是代码托管网站&#xff1a;https://sourceforge.net/projects/freertos/files/FreeRTOS/ 打开代码托管网站链接&#xff0c;我们选择FreeRTOS 的版本 V9…

全域运营平台是什么?优缺点有哪些?

当下&#xff0c;全域运营赛道逐渐兴盛&#xff0c;全域运营服务商的数量也开始呈现爆发趋势。在此背景下&#xff0c;很多人都对某些品牌的全域运营平台优缺点产生了浓厚的兴趣。由于小编只使用过微火全域运营平台&#xff0c;因此&#xff0c;本期会着重分析微火运营平台的优…

【软考】设计模式之桥接模式

目录 1. 说明2. 应用场景3. 结构图4. 构成5. 适用性6. 优点7. 缺点8. java示例 1. 说明 1.将抽象部分与其实现部分分离&#xff0c;使它们都可以独立地变化。2.桥接模式&#xff08;Bridge Pattern&#xff09;属于对象结构型模式&#xff0c;又称为柄体&#xff08;Handle an…

Leetcode2105. 给植物浇水 II

Every day a Leetcode 题目来源&#xff1a;2105. 给植物浇水 II 解法1&#xff1a;双指针 设 Alice 当前下标为 i&#xff0c;初始化为 0&#xff0c;水量为 a&#xff0c;初始化为 capacityA&#xff1b;Bob 当前下标为 j&#xff0c;初始化为 n-1&#xff0c;水量为 b&am…