【Linux 网络编程1】使用UDP/TCP编写套接字,多进程/多线程版本的TCP编写的套接字,将套接字封装
目录
1.学习网络编程前的一些基础知识
2.UDP(user datagram protocol)协议的特点
3.使用有UPD编写套接字
4.使用TCP编写套接字
4.2.TCP客服端
4.3.TCP服务器端
4.4.单进程版本(没有人会使用)
4.5.多进程版本
4.6.多线程版本
5.把套接字封装
1.学习网络编程前的一些基础知识
1.1.IP地址
- IP地址是在IP协议中, 用来标识网络中不同主机的地址(一个IP地址标识一台主机);
- 通常使用 "点分十进制" 的字符串表示IP地址, 例如127.0.0.1 ; 用点分割的每一个数字表示一个字节, 范围是 0 - 255,就是一个字节的大小,IP地址刚好是4字节, 32位的整数;
1.2.端口号(port)
- 端口号是一个2字节16位的整数
- 端口号用来标识一个进程,那么IP地址+端口号就可以标识某一台主机的某一个进程
1.3.TCP/IP四层模型
1.4.网络字节序
- 网络字节序就是大端字节序(低位放在高地址上),使用相同的字节序便于网络间通信;
有系统提供的接口
2.UDP(user datagram protocol)协议的特点
UDP协议是一个传输层协议
- 无连接:没有连接,客户端发给服务器端,服务器端要先保存客户端的信息,服务器端再使用这个信息发给对应的客户端(简单地说就是需要指明发送给谁)
- 不可靠传输:只是传递数据,成功与否都不会反馈
- 面向数据报:不能向面向字节流的TCP一样使用read和write来读写
3.使用有UPD编写套接字
3.1.服务器端
3.1.1.创建套接字
int sock=socket(AF_INET,SOCK_DGRAM,0);//创建套接字if(sock<0){std::cerr<<"socket fail: "<<errno<<std::endl;return 1;}
3.1.2.bind服务器
网络字节序就是大端字节序(低位放在高地址上),使用相同的字节序便于网络间通信;
- 1.需要将人识别的点分十进制,字符串风格IP地址,转化为4字节整数IP.2.考虑大小端的问题
服务器不用bind一个固定的IP的原因
- 1.云服务器,不允许bind公网IP,另外,在一般编写也不会指明IP.2.一般主机有多个IP,如果只是bind一个IP,发给其他IP的数据就不会交给主机处理
- INADDR_ANY只要是发给这个主机的数据都会被处理
struct sockaddr_in local;local.sin_family=AF_INET;local.sin_port=htons(port);//1.需要将人识别的点分十进制,字符串风格IP地址,转化为4字节整数IP.2.考虑大小端的问题//1.云服务器,不允许bind公网IP,另外,在一般编写也不会指明IP.2.一般主机有多个IP,如果只是bind一个IP,发给其他IP的数据就不会交给主机处理;//INADDR_ANY只要是发给这个主机的数据都会被处理local.sin_addr.s_addr=INADDR_ANY;if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)//bind主机{std::cerr << "bind error : " << errno << std::endl;return 2;}
3.1.3.传递接受数据
- UDP是无连接的,需指明发给谁,也需要保存发送端的信息
//业务逻辑char message[1024];bool quit=false;while(!quit){//保存发送端信息struct sockaddr_in peer; socklen_t len=sizeof(peer);//接受数据ssize_t s=recvfrom(sock,message,sizeof(message)-1,0,(struct sockaddr*)&peer,&len);if(s>0){message[s]=0;std::cout<<"client# "<<message<<std::endl;}else{std::cerr<<"recvfrom"<<errno<<std::endl;return 2;}//给对端发送一个你好吗std::string tm="你好吗?";std::cout<<"server to client: "<<tm<<std::endl;sendto(sock,tm.c_str(),tm.size(),0,(struct sockaddr*)&peer,len);}
3.2.客户端
- 客户端不需要显示bind,当传输第一个数据是会自动随机bind一个port(没有被使用的port)
#include<iostream>
#include<cerrno>
#include<string>
#include<cstdlib>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>//client serverIP serverPort
int main(int argc,char* argv[])
{if(argc!=3){std::cout<<"请按格式输入: client serverIP serverPort"<<std::endl;return 2;}int sock=socket(AF_INET,SOCK_DGRAM,0);//创建套接字if(sock<0){std::cout<<"socket create errno: "<<errno<<std::endl;return 1;}//客户端不用显示bind,OS会自动bind;//服务器端会有规划,让port是没有被占用的,让别人来访问这个port;//client正常发送数据的时候,OS会自动给你bind,采用随机端口的方式struct sockaddr_in server;server.sin_family=AF_INET;server.sin_port=htons(atoi(argv[2]));server.sin_addr.s_addr=inet_addr(argv[1]);while(1){std::string message;std::cout<<"请输入#";std::cin>>message;sendto(sock,message.c_str(),message.size(),0,(struct sockaddr*)&server,sizeof(server));struct sockaddr_in tmp;socklen_t tlen=sizeof(tmp);char buffer[1024];ssize_t s=recvfrom(sock,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&tmp,&tlen);if(s>0){std::cout<<"server say#: "<<buffer<<std::endl;buffer[s]=0; }else{std::cerr<<"recvfrom"<<errno<<std::endl;return 2;}}return 0;
}
4.使用TCP编写套接字
4.1.TCP的特点
TCP是一个传输层协议,和UDP的特点相反
- 有连接
- 可靠传输
- 面向字节流
4.2.TCP客服端
先写的客户端,因为服务器端会写多个版本
#include<iostream>
#include<stdio.h>
#include<cerrno>
#include<unistd.h>
#include<string>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>void Usage()
{std::cout<<"usage:./client server_IP server_port"<<std::endl;
}
int main(int argc,char* argv[])
{if(argc!=3){Usage();return 1;}//建立套接字int sock=socket(AF_INET,SOCK_STREAM,0);if(sock<0){std::cerr<<"socket"<<errno<<std::endl;return 2;}//自动bind//连接服务器struct sockaddr_in local;local.sin_addr.s_addr=inet_addr(argv[1]);local.sin_port=htons(atoi(argv[2]));local.sin_family=AF_INET;connect(sock,(struct sockaddr*)&local,sizeof(local));//业务逻辑while(1){char buffer[1024]={0};std::cout<<"请输入";fgets(buffer,sizeof(buffer),stdin);write(sock,buffer,sizeof(buffer));char mes[1024]={0};read(sock,mes,sizeof(mes));std::cout<<mes<<std::endl;}return 0;
}
4.3.TCP服务器端
4.3.1.创建套接字和bind服务器
- socket的第二个参数是SOCK_STREAM,UPD是SOCK_DGRAM(datagram),TCP是SOCK_STREAM(stream,就是字节流)
//建立套接字int listen_sock=socket(AF_INET,SOCK_STREAM,0);if(listen_sock<0){std::cerr<<"socket"<<errno<<std::endl;return 1;}//bind服务器struct sockaddr_in local;local.sin_family=AF_INET;local.sin_port=htons(PORT);local.sin_addr.s_addr=INADDR_ANY;//INADDR_ANY会bind执行代码的主机if(bind(listen_sock,(struct sockaddr*)&local,sizeof(local))<0){std::cerr<<"bind"<<errno<<std::endl;return 2;}
4.3.2.listen设为聆听状态
//listen状态listen(listen_sock,5);
4.3.3.accept接受客户端的连接,并返回一个文件描述符
- 因为TCP套接字是有连接的,连接成功后也是使用返回的套接字和对端进行网络通信
struct sockaddr_in tmp;
socklen_t tlen=sizeof(tmp);
//建立连接
int fd=accept(listen_sock,(struct sockaddr*)&tmp,&tlen);
4.4.单进程版本(没有人会使用)
- 一次只能让一个客户端访问
- 写端关闭读端读到文件结尾,再读返回0
int main()
{//...创建套接字、bind、listen都省略了,每次都一样冗余while(1){struct sockaddr_in tmp;socklen_t tlen=sizeof(tmp);//建立连接int fd=accept(listen_sock,(struct sockaddr*)&tmp,&tlen);if(fd<0){std::cerr<<"accept "<<errno<<std::endl;return 3;}std::cout<<"get a new link "<<std::endl;//1.单进程versionwhile(1){char buffer[1024]={0};ssize_t s=read(fd,buffer,sizeof(buffer));if(s>0){buffer[s]=0;std::cout<<"client to server:"<<buffer<<std::endl;std::string message;message+="server to client:你好!";//给连接的客户端发一个你好write(fd,message.c_str(),message.length());}else if(s==0){//写端关闭读端读到文件结尾,再读返回0std::cout<<"client quit!"<<std::endl;break;}else{std::cerr<<"read "<<errno<<std::endl;break;}}}
}
4.5.多进程版本
4.5.1.父进程是一个循环,他要一直接收新的客服端不能等待子进程,解决方法
-
父进程等待子进程,子进程创建后再创建孙子进程执行后序代码,子进程秒退等待时间可以忽略不计;下面代码
pid_t pid = fork();if(pid<0){continue;}else if(pid==0){//子进程close(listen_sock);if(fork()>0)exit(0);//子进程创建就直接退出,创建的孙子进程执行后序代码,孙子进程变成孤儿进程被1号进程领养serviceIO(fd);close(fd);exit(0);}else{//父进程close(fd);//子进程的PCB以父进程的PCB做模板初始化,不是共享的//waitpid(&pid,NULL,0);//父进程等待子进程,子进程创建后再创建孙子进程执行后序代码,子进程秒退等待时间可以忽略不计}
2.signal(SIGCHLD,SIG_IGN);//忽略SIGCHLD信号,子进程将自动释放;
2.关闭不用的文件描述符,父进程关闭accept返回的文件描述符,子进程关闭socket返回的文件描述符
void serviceIO(const int& fd)
{//1.单进程version,做成一个函数while(1){char buffer[1024]={0};ssize_t s=read(fd,buffer,sizeof(buffer));if(s>0){buffer[s]=0;std::cout<<"client to server:"<<buffer<<std::endl;std::string message;message+="server to client:你好!";//给连接的客户端发一个你好write(fd,message.c_str(),message.length());}else if(s==0){//写端关闭读端读到文件结尾,再读返回0std::cout<<"client quit!"<<std::endl;break;}else{std::cerr<<"read "<<errno<<std::endl;break;}}
}int main()
{//...创建套接字、bind、listen都省略了,每次都一样冗余signal(SIGCHLD,SIG_IGN);//忽略SIGCHLD信号,子进程将自动释放while(1){struct sockaddr_in tmp;socklen_t tlen=sizeof(tmp);//建立连接int fd=accept(listen_sock,(struct sockaddr*)&tmp,&tlen);std::cout<<"get a new link "<<std::endl;if(fd<0){std::cerr<<"accept "<<errno<<std::endl;return 3;}//2.多进程versionpid_t pid = fork();if(pid<0){continue;}else if(pid==0){//子进程close(listen_sock);serviceIO(fd);close(fd);exit(0);}else{//父进程close(fd);//子进程的PCB以父进程的PCB做模板初始化,不是共享的}}
}
4.6.多线程版本
- 线程是共享PCB的,所以在线程内使用完毕关闭文件描述符即可;
- 不等待线程可以使用线程分离的方法
void serviceIO(const int& fd)
{//1.单进程versionwhile(1){char buffer[1024]={0};ssize_t s=read(fd,buffer,sizeof(buffer));if(s>0){buffer[s]=0;std::cout<<"client to server:"<<buffer<<std::endl;std::string message;message+="server to client:你好!";//给连接的客户端发一个你好write(fd,message.c_str(),message.length());}else if(s==0){//写端关闭读端读到文件结尾,再读返回0std::cout<<"client quit!"<<std::endl;break;}else{std::cerr<<"read "<<errno<<std::endl;break;}}
}
void* HandlerRequest(void* agrs)
{pthread_detach(pthread_self());int fd=*((int*)agrs);serviceIO(fd);close(fd);//记得关闭文件描述符
}
int main()
{while(1){struct sockaddr_in tmp;socklen_t tlen=sizeof(tmp);//建立连接int fd=accept(listen_sock,(struct sockaddr*)&tmp,&tlen);std::cout<<"get a new link "<<std::endl;if(fd<0){std::cerr<<"accept "<<errno<<std::endl;return 3;}pthread_t tid;pthread_create(&tid,nullptr,HandlerRequest,(void*)&fd);}return 0;
}
5.把套接字封装
- 使用静态是因为不用创建对象就可以使用sock::Socket()等函数;
#pragma once
#include<iostream>
#include<cstdlib>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>namespace ns_socket{class sock{public:static int Socket(){int sock=socket(AF_INET,SOCK_STREAM,0);if(sock<0){std::cerr<<"socket"<<std::endl;exit(1);}return sock;}static void Bind(int sock,char* port){struct sockaddr_in local;local.sin_family=AF_INET;local.sin_addr.s_addr=INADDR_ANY;local.sin_port=htons(atoi(port));if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0){std::cerr<<"bind"<<std::endl;exit(2);}}static void Listen(int sock){if(listen(sock,5)<0){std::cerr<<"listen"<<std::endl;exit(3);}}static int Accept(int sock) {struct sockaddr_in tmp;socklen_t tlen=sizeof(tmp);int new_sock=accept(sock,(struct sockaddr*)&tmp,&tlen);if(new_sock<0){std::cerr<<"accept"<<std::endl;exit(4);}return new_sock; }static void Connect(int sock,char* server_ip,char* server_port){struct sockaddr_in local;local.sin_family=AF_INET;local.sin_addr.s_addr=inet_addr(server_ip);local.sin_port=htons(atoi(server_port));if(connect(sock,(struct sockaddr*)&local,sizeof(local))<0){std::cerr<<"connect"<<std::endl;exit(5);}else{std::cout<<"connet success"<<std::endl;}}};
}
相关文章:

【Linux 网络编程1】使用UDP/TCP编写套接字,多进程/多线程版本的TCP编写的套接字,将套接字封装
目录 1.学习网络编程前的一些基础知识 2.UDP(user datagram protocol)协议的特点 3.使用有UPD编写套接字 4.使用TCP编写套接字 4.2.TCP客服端 4.3.TCP服务器端 4.4.单进程版本(没有人会使用) 4.5.多进程版本 4.6.多线程版本 5.把套接字封装 1…...

滑动窗口求最大和最小
滑动窗口 要区分最小和最大滑窗,内层while循环的条件和更新结果的地方 核心: 关键的区别在于,最大滑窗是在迭代右移右边界的过程中更新结果,而最小滑窗是在迭代右移左边界的过程中更新结果。 最小滑窗 给定数组 nums࿰…...
跟ChatGPT学量化,菜鸟炒股也不怕
你是一个python资深量化开发工程师,请介绍量化交易的基本框架 量化交易的基本框架包括以下几个步骤: 数据获取:获取市场数据和公司财务数据等,可以使用API接口、爬虫等方式获取。数据清洗和预处理:对获取到的数据进行清…...

扬帆优配|2600亿新能源巨头狂飙!外资唱多中国:再涨15%
全国停摆的危机,正在迫临法国。 大停工正在将法国推向风险境地。法国政府估计,当地时间3月7日,将迸发全国大型停工游行。法国总工会宣告,到时将让全法国停摆。法国担任交通业务的部长级代表克莱蒙博讷正告称,7日将成为…...

ChatGPT技术与商业模式及产业发展布局方案
文章目录模块一:概念模块二:架构模块三:技术模块四:算力模块五:体验模块六:应用模块七:商业模块八:产业模块九:建议结语主要内容: 采用模块化教学方法&#x…...

CIMCAI port ai shipping ai artificial intelligence smart port
上海人工智能独角兽中集集团高科技中集飞瞳,是全球应用落地最广,规模最大,最先进的的港航人工智能高科技企业,工业级成熟港航人工智能产品全球规模化落地应用,全球前三大船公司及港口码头应用落地。上海人工智能独角兽…...

《数据解构》HashMap源码解读
👑作者主页:Java冰激凌 📖专栏链接:数据结构 目录 了解HashMap HashMap的构造 两个参数的构造方法 一个参数的构造方法 不带参数的构造方法 哈希表初始化的长度 HashMap源码中的成员 Pt Get 了解HashMap 首先我们要明…...

Databend 开源周报 第 83 期
Databend 是一款现代云数仓。专为弹性和高效设计,为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务:https://app.databend.com 。Whats New探索 Databend 本周新进展,遇到更贴近你心意的 Databend 。Support for WebHDFSHDFS 是大数…...

Spring | 基础
1. IOC和DI IOC:控制反转,其思想是反转资源获取的方向,传统的资源查找方式要求组件向容器发起请求查找资源,作为回应,容器适时的返回资源。而应用了 IOC 之后,则是**容器主动地将资源推送给它所管理的组件…...

windows7安装sql server 2000安装步骤 及安装过程中遇到的问题和解决方式
提示:文章写完后windows7安装sql server 2000安装步骤 及安装过程中遇到的问题和解决方式, 文章目录一、ms sql server 2000是什么?版本简介:**特点:****优点:**二、步骤1.下载安装包及Sq4补丁包2.安装 ms …...

Python 开发-批量 FofaSRC 提取POC 验证
数据来源 学习内容和目的: ---Request 爬虫技术,lxml 数据提取,异常护理,Fofa 等使用说明---掌握利用公开或 0day 漏洞进行批量化的收集及验证脚本开发Python 开发-某漏洞 POC 验证批量脚本---glassfish存在任意文件读取在默认4…...
Linux系统中部署软件
目录 1.Mysql 2.Redis 3.ZooKeeper 声明 致谢 1.Mysql 参考:CentOS7安装MySQL 补充: ① 执行:rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022 再执行:yum -y install mysql-community-server ② mysql…...
PHP常用框架介绍与比较
HP是一种广泛应用于Web开发的编程语言。随着互联网的快速发展,PHP的应用场景变得越来越广泛,从简单的网站到复杂的Web应用程序都可以使用PHP来开发。为了更好地组织和管理PHP代码,开发人员经常会使用框架来提高开发效率和代码质量。 本文将介绍一些常用的PHP框架,并进行简…...

Umi + React + Ant Design Pro 项目实践(一)—— 项目搭建
学习一下 Umi、 Ant Design 和 Ant Design Pro 从 0 开始创建一个简单应用。 首先,新建项目目录: 在项目目录 D:\react\demo 中,安装 Umi 脚手架: yarn create umi # npm create umi安装成功: 接下来,…...
MySQL知识点总结(1)
目录 1、sql、DB、DBMS分别是什么,他们之间的关系? 2、什么是表? 3、SQL语句怎么分类呢? 4、导入数据 5、什么是sql脚本呢? 6、删除数据库 7、查看表结构 8、表中的数据 10、查看创建表的语句 11、简单的查询…...
day45第九章动态规划(二刷)
今日任务 70.爬楼梯(进阶)322.零钱兑换279.完全平方数 70.爬楼梯(进阶) 题目链接: https://leetcode.cn/problems/climbing-stairs/description/ 题目描述: 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不…...

第十四届蓝桥杯第三期模拟赛原题与详解
文章目录 一、填空题 1、1 找最小全字母十六进制数 1、1、1 题目描述 1、1、2 题解关键思路与解答 1、2 给列命名 1、2、1 题目描述 1、2、2 题解关键思路与解答 1、3 日期相等 1、3、1 题目描述 1、3、2 题解关键思路与解答 1、4 乘积方案数 1、4、1 题目描…...

client打包升级
目录 前言 一、client如何打包升级? 二、使用步骤 1.先进行改版本 2.执行打包升级命令 总结 前言 本文章主要记录一下,日常开发中,常需要进行打包升级的步骤。 一、client如何打包升级? # 升级发布版本 ## 修改版本 * 父p…...

Blazor_WASM之3:项目结构
Blazor_WASM之3:项目结构 Blazor WebAssembly项目模板可选两种,Blazor WebAssemblyAPP及Blazor WebAssemblyAPP-Empty 如果使用Blazor WebAssemblyAPP模板,则应用将填充以下内容: 一个 FetchData 组件的演示代码,该…...
OperWrt 包管理系统02
文章目录 OperWrt 包管理系统OPKG简介OPKG的工作原理OPKG命令介绍软件包的更新、安装、卸载和升级等功能软件包的信息查询OPKG配置文件说明OPKG包结构(.ipk)OPKG演示案例OperWrt 包管理系统 OPKG简介 OPKG(Open/OpenWrt Package)是一个轻量快速的软件包管理系统,是 IPKG…...

python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...

高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...

【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...

Xcode 16 集成 cocoapods 报错
基于 Xcode 16 新建工程项目,集成 cocoapods 执行 pod init 报错 ### Error RuntimeError - PBXGroup attempted to initialize an object with unknown ISA PBXFileSystemSynchronizedRootGroup from attributes: {"isa">"PBXFileSystemSynchro…...

使用python进行图像处理—图像变换(6)
图像变换是指改变图像的几何形状或空间位置的操作。常见的几何变换包括平移、旋转、缩放、剪切(shear)以及更复杂的仿射变换和透视变换。这些变换在图像配准、图像校正、创建特效等场景中非常有用。 6.1仿射变换(Affine Transformation) 仿射变换是一种…...