Linux下套接字TCP实现网络通信
Linux下套接字TCP实现网络通信
文章目录
- Linux下套接字TCP实现网络通信
- 1.引言
- 2.具体实现
- 2.1接口介绍
- 1.socket()
- 2.bind()
- 3.listen()
- 4.accept()
- 5.connect()
- 2.2 服务器端server.hpp
- 2.3服务端server.cc
- 2.4客户端client.cc
1.引言
套接字(Socket)是计算机网络中实现网络通信的一种编程接口。它提供了应用程序与网络通信之间的一座桥梁,因为它允许应用程序通过网络发送和接收相应的数据以实现不同主机之间的通信。
通常套接字由以下两部分组成:
1.网络IP和端口号:IP用来标识主机,而端口号可以标识到单台主机的唯一进程。
2.通信协议:套接字通过规定通信协议来制定数据传输和发送的规则。常见的有TCP和UDP等协议。
TCP是一种面向连接的协议,提供可靠的、有序的、基于字节流的数据传输。
UDP是一种无连接的协议,提供不可靠的、无序的、基于数据报的数据传输。
今天我们来学习TCP实现网络通信。TCP由于能提供可靠、基于字节流的数据传输,使用率与使用场景也比UDP多很多。
我们来看看能实现出什么样的结果(聊天室模拟两个用户随机通信):
若不开启服务端就只开启客户端的话,那么就会像打游戏的某些情况连不上:
当服务端和客户端都开启后就可以正常通信了:
这里我们还是通过客户端给服务器端发送消息,通过TCP链接实现通信。
那么事不宜迟,我们马上开始分享实现过程吧!
2.具体实现
2.1接口介绍
1.socket()
socket函数是用于创建套接字的函数,创建成功返回文件描述符fd,失败返回-1;
int socket(int domain, int type, int protocol);
参数说明:
-
domain
:指定套接字的地址族(Address Family)
今天我们选择:
AF_INET
:IPv4 地址族
-
type
:指定套接字的类型(Socket Type)
今天我们选择:
SOCK_STREAM
:有连接的字节流套接字,用于TCP协议
-
protocol
:可选参数,指定具体的传输协议。常用的有:
今天我们选择:
0
:自动选择合适的协议
2.bind()
在Linux下,bind()
函数用于将一个套接字(socket)与特定的IP地址和端口号进行绑定。
*int bind(int sockfd, const struct sockaddr addr,socklen_t addrlen);
参数说明:
sockfd
:要进行绑定的套接字的文件描述符。addr
:指向一个struct sockaddr
结构体的指针,其中包含要绑定的IP地址和端口号信息。addrlen
:addr
结构体的长度。
在绑定bind的第二个参数中,我们也需要用到库中定义好的sockaddr_in结构体来初始化!
具体结构体struct sockaddr_in说明:
结构体中有三个值也需要初始化指定一下:
sin_family
:表示地址族(Address Family),一般为AF_INET
。
sin_port
:表示端口号。它是一个 16 位的整数,使用网络字节序(大端字节序)表示。在使用时,通常需要使用htons()
函数将主机字节序转换为网络字节序。
sin_addr
:表示 IPv4 地址。它是一个struct in_addr
类型的结构体,用于存储 32 位的 IPv4 地址。一般服务端用INADDR_ANY,让udp_server在启动时候可以绑定任何ip.
客户端用inet_addr函数将字符串转化成32位无符号整数
3.listen()
listen()函数:
将套接字设置为监听状态,等待连接请求。
参数:
- sockfd:套接字的文件描述符。这里我们选择前面socket创建好的返回值.
- backlog:指定等待连接队列的最大长度。一般不会太大,我们这里写32即可。
4.accept()
accept()
函数:接受客户端的连接请求,创建一个新的套接字用于与客户端进行通信。
参数:
- sockfd:套接字的文件描述符。这里我们选择前面socket创建好的返回值.
- addr:指向客户端地址的结构体指针。创建一个sockaddr的结构体强转一下(struct sockaddr*)即可。
- addrlen:客户端地址结构体的字节大小。创建一个socklen_t类型的值用来计算结构体大小。
5.connect()
connect()
函数:发起与远程主机建立TCP连接的请求。
参数:
- sockfd:套接字的文件描述符。这里我们选择前面socket创建好的返回值.
- addr:指向远程主机地址的结构体指针。创建一个sockaddr的结构体强转一下(struct sockaddr*)即可。
- addrlen:远程主机地址结构体的字节大小。创建一个socklen_t类型的值用来计算结构体大小。
2.2 服务器端server.hpp
在整个服务器端server.hpp中,我们需要创建tcpServer类,并在类中建立这些成员:监听套接字、端口号等.
在类中我们还需要初始化服务器InitServer()和启动服务器Start()两个接口。
服务器端具体实现思路是:我们创建套接字socket()后开始绑定bind(),之后监听listen(),监听成功后我们获取链接accept()即可。
思路简单,但是实现还需要很多事完成:
static const uint16_t defaultport = 8081;
static const int backlog = 32;
using func_t = std::function<std::string(const std::string&)>;class tcpServer
{public:tcpServer(func_t func,uint16_t port = defaultport):_func(func),_port(port),_quit(true){}~tcpServer() {}void InitServer(){//1.创建套接字_listensock = socket(AF_INET,SOCK_STREAM,0);if(_listensock < 0){std::cerr << "create socket error" << std::endl;exit(-1);}//2.绑定struct sockaddr_in local;memset(&local,0,sizeof(local)); //清空结构体local.sin_family = AF_INET;local.sin_port = htons(_port); //主机转网络local.sin_addr.s_addr = htonl(INADDR_ANY);if(bind(_listensock,(struct sockaddr*)&local,sizeof(local)) < 0){std::cerr << "bind error" << std::endl;exit(-2);}//3.监听(tcp)if(listen(_listensock,backlog) < 0){std::cerr <<" listen error" << std::endl;exit(-3);}}void Start(){_quit = false; //运行时设置位运行状态,即不退出的状态while(!_quit) //服务器死循环{struct sockaddr_in client;socklen_t len = sizeof(client);//4.获取链接acceptint sock = accept(_listensock,(struct sockaddr*)&client,&len);if(sock < 0) {std::cerr <<"accept error " <<std::endl;continue;} //揽客的sock失败后继续即可//5.获取链接成功std::cout<< "获取链接成功" << sock << " from " << _listensock << std::endl;service(sock);}}void service(int sock) //服务{char buffer[1024];while(true){ssize_t s = read(sock,buffer,sizeof(buffer)-1);if(s > 0) //代表成功读取{buffer[s] = 0;std::string res = _func(buffer); //回调显示std::cout<< res <<std::endl;write(sock,res.c_str(),res.size());}else if(s == 0) //代表读到文件结尾 在网络中就相当于对方关闭链接{close(sock);std::cout << "quit" <<std::endl;break;}else //文件读取失败{close(sock);std::cerr << " read error" <<std::endl;break;}}}private:uint16_t _port; //端口号int _listensock; //监听套接字bool _quit; //代表服务器没有运行的状态func_t _func; //回调包装器,为了后面输出后回显
};
2.3服务端server.cc
在服务端的主文件中,我们直接包含上面的头文件。
我们期望的用法是:./tcp_server port,代表运行可执行文件后面需要带一个参数:端口号
所以我们能够从用户中输入的port,通过main函数中的**char* argv[]**参数列表中获取到。并传给tcpSercer类中初始化与启动服务器即可。
#include "server.hpp"
#include<memory>
using namespace std;static void usage(string proc) //使用手册,代表运行可执行文件后面需要带一个参数:端口号
{std::cout << "Usage:\n\t" << proc << "port\n" <<std::endl;}std::string echo(const std::string& message)//输出回显
{return message;
}//期望用法:./tcp_server port
int main(int argc,char* argv[])
{if(argc != 2) //输入的不是两个参数,说明你不会用。输出使用手册{usage(argv[0]);exit(-1);}uint16_t port = atoi(argv[1]); //强转成能够使用的类型unique_ptr<tcpServer> ts(new tcpServer(echo,port));//采用智能指针创建释放资源ts->InitServer();ts->Start();return 0;
}
2.4客户端client.cc
在客户端中我们conncet尝试链接到服务器端,这里需要做一个重连反馈:正在尝试重连…
我们期望运行格式:./client serverip serverport,代表运行可执行文件后需要两个参数:IP和端口
我们从用户输入的两个参数中传给main,并通过main参数char* argv[]参数列表获取到,之后获取到直接转化即可。
static void usage(string proc)
{std::cout << "Usage:\n\t" << proc << "serverip serverport\n" <<std::endl;}
//期望使用:./client serverip serverport
int main(int argc,char* argv[])
{if(argc != 3){usage(argv[0]);exit(-2);}string serverip = argv[1]; //获取到参数uint16_t port = atoi(argv[2]);//1.创捷套接字int sock = socket(AF_INET,SOCK_STREAM,0);if(sock < 0){std::cerr << " socket error" <<std::endl;exit(-1);}//2.客户端需要链接服务器 --connectstruct sockaddr_in server; //memset(&server,0,sizeof(server)); //清空结构体server.sin_family = AF_INET;//初始化结构体server.sin_port = htons(port);//server.sin_addr.s_addr = inet_addr(serverip.c_str()); //客户端inet_aton(serverip.c_str(),&(server.sin_addr));int cnt = 5;while(connect(sock,(struct sockaddr*)&server,sizeof(server)) != 0) //如果绑定失败{sleep(1);std::cout<<"正在尝试重连... 重连次数:" <<cnt-- <<std::endl;if(cnt <= 0) break;} if(cnt <= 0){cerr<< "服务器连接失败"<<endl;exit(-1);}//3.连接成功while(true) //连接成功后从客户端直接输入发送数据{string line;char buffer[1024];cout<<"Enter>> "; getline(cin,line);write(sock,line.c_str(),line.size()); //给缓冲区写数据ssize_t s = read(sock,buffer,sizeof(buffer) -1);if(s > 0)//正常写{buffer[s] = 0;cout<< " server rcho >>>" <<buffer <<endl;}else if(s == 0) //写结束{cerr << "server quit" <<endl;break;}else{ //异常cerr<< " read error " <<endl;break;}}close(sock);//关闭套接字,管不管都可以return 0;
}
最后运行之后就能获得我们之前通信的结果了:
相关文章:

Linux下套接字TCP实现网络通信
Linux下套接字TCP实现网络通信 文章目录 Linux下套接字TCP实现网络通信1.引言2.具体实现2.1接口介绍1.socket()2.bind()3.listen()4.accept()5.connect() 2.2 服务器端server.hpp2.3服务端server.cc2.4客户端client.cc 1.引言 套接字(Socket)是计算机网络中实现网络通信的一…...
❤ vue清除定时器Bug
❤ vue清除定时器Bug 页面加载,清除定时器 clearTimeout(intm) 问题 遇见的需求是:webapp 从A页面进入B页面,B页面点击按钮,加载完B页面的加载效果进入c,从C页面返回A页面,仍然显示B页面的加载效果 结果定时器一直…...

IDEA创建Spring,Maven项目没有resources文件夹
有时新建Spring或Maven项目时,会出现目录中main下无resources文件夹的情况,来一起解决一下: FIles|Project Structure 在Modules模块找到对应路径,在main下创建resources,右键main,选择新文件夹 输入文件…...

Unity 结构少继承多组合
为什么不推荐使用继承? 继承是面向对象的四大特性之一,用来表示类之间的 is-a 关系,可以解决代码复用的问题。虽然继承有诸多作用,但继承层次过深、过复杂,也会影响到代码的可维护性。所以,对于是否应该在…...
保研之旅2:中科院声学所“声学和信息学科”夏令营
💥💥💞💞欢迎来到本博客❤️❤️💥💥 本人持续分享更多关于电子通信专业内容以及嵌入式和单片机的知识,如果大家喜欢,别忘点个赞加个关注哦,让我们一起共同进步~ &#x…...
android adb自动连接手机安装apk bat
1.新建bat文件adb echo off:apk文件名称 在setting.txt获取 set apkFileName"":设置文件 set settingFileE:\apk\bat\setting.txt:启动页面 applicationid/启动页面路径 set startActivitycom.aaa.aaa/com.aaa.aaa.ui.common.SplashActivity:读取settingFile第一行的…...

用心维护好电脑,提高学习工作效率
无论是学习还是工作,电脑都是IT人必不可少的重要武器,一台好电脑除了自身配置要经得起考验,后期主人对它的维护也是决定它寿命的重要因素! 一、我的电脑 系统制造商: ASUSTeK COMPUTER INC. 系统型号: ZenBook UX481FAY 1.1 如…...
以太坊硬分叉后的可重入漏洞攻击
以太坊硬分叉后的可重入漏洞攻击 以太坊君士坦丁堡升级将降低部分 SSTORE 指令的 gas 费用。然而,这次升级也有一个副作用,在 Solidity 语言编写的智能合约中调用 address.transfer()函数或 address.send()函数时存在可重入漏洞。在目前版本的以太坊网络…...

k8s 常用命令(三)
1、查看版本信息:kubectl version [rootmaster ~]# kubectl version [rootmaster ~]# kubectl version Client Version: version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.3", GitCommit:"ca643a4d1f7bfe34773c74f7952…...

API 网关基础
目录 一、网关概述二、网关提供的功能三、常见网关系统3.1 Netflix Zuul3.2 Spring Cloud Gateway3.3 Kong3.4 APISIX3.5 Shenyu 一、网关概述 API网关是一个服务器,是系统的唯一入口。 从面向对象设计的角度看,它与外观模式类似。API网关封装了系统内部…...

【Linux】权限问题
Linux权限 一、Linux 权限的概念二、Linux 权限管理1. 文件访问者的分类2. 文件类型和访问权限(事物属性)3. 文件访问权限的相关设置方法 三、默认权限1. 对文件和目录进行操作需要的权限2. 文件和目录的默认权限3. 粘滞位 一、Linux 权限的概念 Linux …...

线性代数的学习和整理10:各种特殊类型的矩阵(草稿-----未完成 建设ing)
目录 1 图形化分类 1.1对称矩阵 1.2 梯形矩阵 1.3 三角矩阵 1.3.1 上三角矩阵 1.4 对角线矩阵 2 按各自功能分 2.1 等价矩阵 2.2 增广矩阵 2.3 伴随矩阵 2.4 正交矩阵 2.5 正交矩阵 2.6 相似矩阵 1 图形化分类 1.1对称矩阵 1.2 梯形矩阵 1.3 三角矩阵 1.3.1 上…...
Go 自学:变量、函数、结构体、接口、错误处理
1. 打印变量数据类型 package mainimport "fmt"func main() {penniesPerText : 2.0fmt.Printf("The type of penniesPerText is %T\n", penniesPerText) }输出为: The type of penniesPerText is float64 2. 同时给多个变量赋值 package mai…...

pyqt Pyton VTK 使用 滑块 改变 VTK Actor 颜色
使用 PyQt5 vtk vtk球体 使用滑块 RGB 改变 Actor 颜色 CODE import sys from PyQt5.QtWidgets import * from PyQt5.QtWidgets import (QApplication, QCheckBox, QGridLayout, QGroupBox,QMenu, QPushButton, QRadioButton, QVBoxLayout, QWidget, QSlider,QLineEdit,QLabe…...

春秋云镜 CVE-2019-16113
春秋云镜 CVE-2019-16113 Bludit目录穿越漏洞 靶标介绍 在Bludit<3.9.2的版本中,攻击者可以通过定制uuid值将文件上传到指定的路径,然后通过bl-kernel/ajax/upload-images.php远程执行任意代码。 启动场景 漏洞利用 exp https://github.com/Kenun…...

【JavaEE基础学习打卡06】JDBC之进阶学习PreparedStatement
目录 前言一、PreparedStatement是什么二、重点理解预编译三、PreparedStatement基本使用四、Statement和PreparedStatement比较1.PreparedStatement效率高2.PreparedStatement无需拼接参数3.PreparedStatement防止SQL注入 总结 前言 📜 本系列教程适用于JavaWeb初学…...
Postgresql12基于时间点恢复
1、环境 centos 7系统 postgresql 12 docker 20.10.6 2、整体思路 1)进行一个pgdata目录的全量备份 2)通过wal日志恢复到故障发生之前某个时间点 3、操作步骤 配置postgresql.conf文件 #日志级别 wal_level replica #归档开关 archive_mode on …...

【MySQL系列】Select语句单表查询详解(二)ORDERBY排序
💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃个人主页 :阿然成长日记 …...
C++学习第十九天----简单文件输入/输出和今日工作问题
1.写入到文本文件中 cout用于控制台输出; 必须包含头文件iostream; 头文件iostream定义了一个用于处理输出的ostream类; 头文件iostream声明了一个名为cout的ostream变量(对象); 必须指明名称空间std&…...

基于风险的漏洞管理
基于风险的漏洞管理涉及对即将被利用的漏洞的分类响应,如果被利用,可能会导致严重后果。本文详细介绍了确定漏洞优先级时要考虑的关键风险因素,以及确保基于风险的漏洞管理成功的其他注意事项。 什么是基于风险的漏洞管理对基于风险的漏洞管…...

超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...

【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
深入浅出Diffusion模型:从原理到实践的全方位教程
I. 引言:生成式AI的黎明 – Diffusion模型是什么? 近年来,生成式人工智能(Generative AI)领域取得了爆炸性的进展,模型能够根据简单的文本提示创作出逼真的图像、连贯的文本,乃至更多令人惊叹的…...

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...