Linux——网络通信TCP通信常用的接口和tcp服务demo

文章目录

  • TCP通信所需要的套接字
    • socket()
    • bind()
    • listen()
    • accept
    • connect()
  • 封装TCP socket

TCP通信所需要的套接字

socket()

socket()函数主要作用是返回一个描述符,他的作用就是打开一个网络通讯端口,返回的这个描述符其实就可以理解为一个文件描述符,tcp在通讯的时候是会开辟一个缓存空间的,我们发送和读取消息可以理解为在这个缓存空间中进行的。因此这里我们可以知道我们可以直接用write和read函数进行消息的写入和读取,如果socket()调用出错则返回-1;
对于IPv4, family参数指定为AF_INET;
对于TCP协议,type参数指定为SOCK_STREAM, 表示面向流的传输协议
protocol参数的介绍从略,指定为0即可。
代码如下以ipv4协议为例

int socketfd=socket(AF_INET,SOCK_STREAM,0)

bind()

bind()函数的作用是为了让socket返回的描述符与端口号进行绑定在bind函数之前我们还需要做一个工作就是将我们的信息存入一个结构体sockaddr_in中,struct sockaddr *是一个通用指针类型,myaddr参数实际上可以接受多种协议的sockaddr结构体,而它们的长度各不相同,所以需要第三个参数addrlen指定结构体的长度
在这里插入图片描述
我们的程序中对myaddr参数是这样初始化的:

sockaddr_in local;
bzero(&local, sizeof(local));//将整个结构体清0
local.sin_port = htons(port_);//porty_是我们的端口号这里是将这个端口号转化为网络序列一般我们的端口号都设置为8000以上
local.sin_family = AF_INET;//设置地址类型为AF_INET
inet_aton(ip_.c_str(), &(local.sin_addr));//网络地址为INADDR_ANY, 这个宏表示本地的任意IP地址,因为服务器可能有多个网卡,每个网卡也可能绑定多个IP 地址, 这样设置可以在所有的IP地址上监听,直到与某个客户端建立了连接时才确定下来到底用哪个IP 地址;

listen()

在这里插入图片描述
liasten函数生命socketfd正处于监听状态并且最多可以允许backlog个客户端处于连接等待状态如果收到更多连接请求就会忽略
listen成功返回0 失败则是-1

accept

在这里插入图片描述
accept函数是为了接受来自客户端的连接请求的函数它是在三次握手之后发挥作用,这里也会有一些问题比如说accept发挥作用的时候此时并没有客户发送连接请求该怎么办呢?这里会陷入阻塞等待的状态也就是一直等到有连接请求为止。

connect()

在这里插入图片描述
客户端需要调用connect()连接服务器;
connect和bind的参数形式一致, 区别在于bind的参数是自己的地址, 而connect的参数是对方的地址;
connect()成功返回0,出错返回-1

封装TCP socket

tcp_socket.hpp

#pragma once
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <string>
#include <cassert>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
typedef struct sockaddr sockaddr;
typedef struct sockaddr_in sockaddr_in;
#define CHECK_RET(exp) if (!(exp)) {\
 return false;\
}
class TcpSocket {
public:
 TcpSocket() : fd_(-1) { }
 TcpSocket(int fd) : fd_(fd) { }
 bool Socket() {
 fd_ = socket(AF_INET, SOCK_STREAM, 0);
 if (fd_ < 0) {
 perror("socket");
 return false;
 }
 printf("open fd = %d\n", fd_);
 return true;
 }
 bool Close() const {
 close(fd_);
 printf("close fd = %d\n", fd_);
 return true;
 }
 bool Bind(const std::string& ip, uint16_t port) const {
 sockaddr_in addr;
 addr.sin_family = AF_INET;
 addr.sin_addr.s_addr = inet_addr(ip.c_str());
 addr.sin_port = htons(port);
 int ret = bind(fd_, (sockaddr*)&addr, sizeof(addr));
 if (ret < 0) {
 perror("bind");
 return false;
 }
 return true;
 }
 bool Listen(int num) const {
 int ret = listen(fd_, num);
 if (ret < 0) {
 perror("listen");
 return false;
 }
 return true;
 }
 bool Accept(TcpSocket* peer, std::string* ip = NULL, uint16_t* port = NULL) const {
 sockaddr_in peer_addr;
 socklen_t len = sizeof(peer_addr);
 int new_sock = accept(fd_, (sockaddr*)&peer_addr, &len);
 if (new_sock < 0) {
 perror("accept");
 return false;
 }
 printf("accept fd = %d\n", new_sock);
 peer->fd_ = new_sock;
 if (ip != NULL) {
 *ip = inet_ntoa(peer_addr.sin_addr);
 }
 if (port != NULL) {
 *port = ntohs(peer_addr.sin_port);
 }
 return true;
 }
 bool Recv(std::string* buf) const {
 buf->clear();
 char tmp[1024 * 10] = {0};
 // [注意!] 这里的读并不算很严谨, 因为一次 recv 并不能保证把所有的数据都全部读完
 // 参考 man 手册 MSG_WAITALL 节. 
 ssize_t read_size = recv(fd_, tmp, sizeof(tmp), 0);
 if (read_size < 0) {
 perror("recv");
 return false;
 }
 if (read_size == 0) {
 return false;
 }
 buf->assign(tmp, read_size);
 return true;
 }
 bool Send(const std::string& buf) const {
 ssize_t write_size = send(fd_, buf.data(), buf.size(), 0);
 if (write_size < 0) {
 perror("send");
 return false;
 }
 return true;
 }
 bool Connect(const std::string& ip, uint16_t port) const {
 sockaddr_in addr;
 addr.sin_family = AF_INET;
 addr.sin_addr.s_addr = inet_addr(ip.c_str());
 addr.sin_port = htons(port);
 int ret = connect(fd_, (sockaddr*)&addr, sizeof(addr));
 if (ret < 0) {
 perror("connect");
 return false;
 }
 return true;
 }
 int GetFd() const {
 return fd_;
 }
 private:
 int fd_;
};

tcp_server.hpp

#pragma once
#include <functional>
#include "tcp_socket.hpp"
typedef std::function<void (const std::string& req, std::string* resp)> Handler;
class TcpServer {
public:
 TcpServer(const std::string& ip, uint16_t port) : ip_(ip), port_(port) {
 }
 bool Start(Handler handler) {
 // 1. 创建 socket;
 CHECK_RET(listen_sock_.Socket());
 // 2. 绑定端口号
 CHECK_RET(listen_sock_.Bind(ip_, port_));
 // 3. 进行监听
 CHECK_RET(listen_sock_.Listen(5));
 // 4. 进入事件循环
 for (;;) {
 // 5. 进行 accept
 TcpSocket new_sock;
 std::string ip;
 uint16_t port = 0;
 if (!listen_sock_.Accept(&new_sock, &ip, &port)) {
 continue;
 }
 printf("[client %s:%d] connect!\n", ip.c_str(), port);
 // 6. 进行循环读写
 for (;;) {
 std::string req;
 // 7. 读取请求. 读取失败则结束循环
 bool ret = new_sock.Recv(&req);
 if (!ret) {
 printf("[client %s:%d] disconnect!\n", ip.c_str(), port);
 // [注意!] 需要关闭 socket
 new_sock.Close();
 break;
 }
 // 8. 计算响应
 std::string resp;
 handler(req, &resp);
 // 9. 写回响应
 new_sock.Send(resp);
printf("[%s:%d] req: %s, resp: %s\n", ip.c_str(), port,
 req.c_str(), resp.c_str());
 }
 }
 return true;
 }
private:
 TcpSocket listen_sock_;
 std::string ip_;
 uint64_t port_;
};
我们开开心心的在一起

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

外包干了3个多月,技术退步明显。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;19年通过校招进入广州某软件公司&#xff0c;干了接近3年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

ElasticSearch高级功能

目录 ES数据预处理 Ingest Node Ingest Node VS Logstash Ingest Pipeline Painless Script ES文档建模 Elasticsearch中处理关联关系 对象类型 嵌套对象(Nested Object) 父子关联关系(Parent / Child ) ES数据预处理 Ingest Node Elasticsearch 5.0后&#xff0c;…

从可靠性的角度理解 tcp

可靠性是 tcp 最大的特点。常见的用户层协议&#xff0c;比如 http, ftp, ssh, telnet 均是使用的 tcp 协议。可靠性&#xff0c;即从用户的角度来看是可靠的&#xff0c;只要用户调用系统调用返回成功之后&#xff0c;tcp 协议栈保证将报文发送到对端。引起不可靠的表现主要有…

频段划分学习射频知识的意义

一、射频电路设计与低频电路设计的不同点 随着频率提高&#xff0c;相应电磁波的波长与变得可与分立电路元件的尺寸相比拟时&#xff0c;电阻、电容和电感这些元件的电响应&#xff0c;将偏离他们的理想频率特性。以 WIFI 2.4G 频段为例&#xff0c;当频率为 2437MHz&#xff0…

【QT】QFile读取.txt文本文件时,中文乱码问题(已解决)

目录 0.背景 1.修改方法 0.背景 项目读取一个【.txt】文本文件&#xff0c;显示到下拉框中&#xff0c;其中含有中文&#xff0c;在读取中文相关字段时会出现乱码&#xff0c;代码和显示如下 .txt文本内容如下&#xff08;显示到下拉框时&#xff0c;我做了分割处理&#xff…

代码随想录 Leetcode509. 斐波那契数

题目&#xff1a; 代码&#xff08;首刷自解 2024年2月19日&#xff09;&#xff1a; class Solution { public:int fib(int n) {if (n < 2) return n;/*三个数表示加法算式里的 加数 加数 和*//*初始化*/int leftVal 0;int rightVal 1;int sum 0;for (int i 2; i <…

智慧城市的新宠儿:会“思考”的井盖

在城市化飞速发展的今天&#xff0c;我们或许未曾过多地关注那些平凡却至关重要的井盖。它们无声地矗立在城市的每个角落&#xff0c;守护着深藏于地下的城市生命线&#xff0c;然而&#xff0c;这些井盖并未满足于传统的角色&#xff0c;它们正逐步融入智慧城市的宏大画卷中&a…

【Go语言】Go语言的数据类型

GO 语言的数据类型 Go 语言内置对以下这些基本数据类型的支持&#xff1a; 布尔类型&#xff1a;bool 整型&#xff1a;int8、byte、int16、int、uint、uintptr 等 浮点类型&#xff1a;float32、float64 复数类型&#xff1a;complex64、complex128 字符串&#xff1a;st…

Git基本操作(1)

Git基本操作&#xff08;1&#xff09; 初始化git本地仓库git本地仓库配置git config user.name 和git config user.emailgit config --unset user.name和git config --unset user.emailgit config --global 认识工作区&#xff0c;暂存区&#xff0c;版本库更深层次理解 git a…

Leetcoder Day15| 二叉树 part04

语言&#xff1a;Java/C 110.平衡二叉树 给定一个二叉树&#xff0c;判断它是否是高度平衡的二叉树。 本题中&#xff0c;一棵高度平衡二叉树定义为&#xff1a; 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。 输入&#xff1a;root [3,9,20,null,null,15,…

使用LangChain结合通义千问API基于自建知识库的多轮对话和流式输出

使用LangChain结合通义千问API基于自建知识库的多轮对话和流式输出 本文章的第三弹&#xff0c;由于LangChain本文不支持直接使用通义千问API进行多轮对话和流式输出&#xff0c;但是自建知识库呢&#xff0c;还需要LangChain,因此我尝试了一下&#xff0c;自建知识库用LangCh…

OpenAI最新Sora视频学习与生成的技术分析与最新体验渠道

前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff1a;https://www.captainbed.cn/z ChatGPT体验地址 文章目录 前言OpenAI体验通道Spacetime Latent Patches 潜变量时空碎片, 建构视觉语言系统…

Unity之闪电侠大战蓝毒兽(简陋的战斗系统)

目录 &#x1f3a8;一、创建地形 &#x1f3ae;二、创建角色 &#x1f3c3;2.1 动画 &#x1f3c3;2.2 拖尾 &#x1f3c3;2.3 角色控制 ​&#x1f3c3;2.4 技能释放 &#x1f3c3;2.5 准星 &#x1f4f1;三、创建敌人 &#x1f432;3.1 选择模型 &#x1f432;3.…

UI美化stylesheet

一、网上找到自己喜欢的图标 大家可以每个图标类型找出三种不同的颜色&#xff0c;方便后续美化效果&#xff0c;这里我每种只找了一个。&#xff08;随便找的&#xff0c;最后效果不好看&#xff09; 将这个文件夹复制到项目的文件夹中。 然后右键Add New…选择QT&#xff0c…

小迪安全27WEB 攻防-通用漏洞SQL 注入Tamper 脚本Base64Jsonmd5 等

#知识点&#xff1a; 1、数据表现格式类型注入 2、字符转义绕过-宽字节注入 3、数字&字符&搜索&编码&加密等 #参考资料&#xff1a; https://www.cnblogs.com/bmjoker/p/9326258.html 扫描&#xff0c;利用工具等都不会自动判断数据类型&#xff0c…

常见面试题:TCP的四次挥手和TCP的滑动窗口

说一说 TCP 的四次挥手。 挥手即终止 TCP 连接&#xff0c;所谓的四次挥手就是指断开一个 TCP 连接时。需要客户端和服务端总共发出四个包&#xff0c;已确认连接的断开在 socket 编程中&#xff0c;这一过程由客户端或服务端任意一方执行 close 来触发。这里我们假设由客户端…

胶管生产中可自动控制外径的测径仪 你心动吗?

摘要&#xff1a;在线测径仪是测控一体的精密仪器&#xff0c;PID闭环控制方法&#xff0c;提升产品外径质量&#xff0c;可以说连测带控才是真绝色&#xff0c;为胶管品质负责。 关键词&#xff1a;胶管测径仪,测径仪,在线测径仪,外径测量仪,直径测量仪 引言 胶管应用领域众多…

2024最新软件测试面试题(带答案)

1. 请自我介绍一下(需简单清楚的表述自已的基本情况&#xff0c;在这过程中要展现出自信&#xff0c;对工作有激情&#xff0c;上进&#xff0c;好学) 面试官您好&#xff0c;我叫###&#xff0c;今年26岁&#xff0c;来自江西九江&#xff0c;就读专业是电子商务&#xff0c;毕…

若依不分离版本部署流程

一、分离与不分离的区别 参考博客&#xff1a;前后端分离与不分离的本质区别&#xff01;_前后端分离本质-CSDN博客 概念适用场景前后端不分离前端页面看到的效果都是由后端控制&#xff0c;由后端渲染页面或重定向适合纯网页应用前后端分离后端仅返回前端所需的数据&#xf…

《汇编语言》- 读书笔记 - 实验 10 编写子程序

《汇编语言》- 读书笔记 - 实验 10 编写子程序 1. 显示字符串问题子程序描述 show_str提示结果演示 2. 解决除法溢出的问题问题子程序描述 divdw提示结果演示 3. 数值显示问题子程序描述 dtoc提示结果演示 在这次实验中&#xff0c;我们将要编写3个子程序&#xff0c;通过它们来…