TCP服务器—实现数据通信

2023-11-18

目录

前言

1.接口介绍

2.编写服务器

3.编写客户端

4.编译链接

5.测试

6.总结


前言

        今天我们要介绍的是使用TCP协议实现数据通信,相比于之前写的UDP服务器实现数据信,在主体逻辑上并没有差别。客户端向服务器发送信息,服务器接受信息并回显,因为UDP是面向数据报,而TCP是面向连接的,所以在实现的时候接口上会有一些差别,下面,我们具体来看看UDP和TCP在编码的实现上有什么不同。

1.接口介绍

因为TCP是面向连接的,所以服务器创建完套接字,然后绑定成功后,将套接字设置为监听套接字

服务器启动之后,首先需要根据监听套接字建立连接,建立连接成功后返回一个新的文件描述符,后续的通信都是按照这个新的文件描述符按照读写文件的形式进行读写数据。

对于客户端来说创建完套接字之后,客户端启动之后首先需要建立连接

listen():设置sock为监听状态

 #include <sys/types.h>       
 #include <sys/socket.h>
 int listen(int sockfd, int backlog);

sockfd:创建套接字的返回值

backlog:底层全连接队列的长度

accept():服务端建立连接

#include <sys/types.h>         
#include <sys/socket.h>

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

sockfd:监听套接字

struct sockaddr* addr:输出型参数,可以获取服务端的IP地址和port端口号

socklen_t* addrlen:结构体的大小

返回值:返回一个新打开的文件描述符

connect():客户端建立连接

#include <sys/types.h>        
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

sockfd:创建套接字返回值

struct sockaddr* addr:输出型参数,用来填写需要访问的服务端的IP地址和port端口号

socklen_t addrlen:结构体的大小

2.编写服务器

tcpServer.hpp

#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "log.hpp"
namespace server
{
    using namespace std;
    enum
    {
        USAGE_ERR = 1,
        SOCKET_ERR,
        BIND_ERR,
        LISTEN_ERR
    };
    static const uint16_t gport = 8080;
    static const int gback = 5;
    class TcpServer
    {
    public:
        TcpServer(const uint16_t &port = gport)
            : _port(gport), _sock(-1)
        {}
        void InitServer()
        {
            _sock = socket(AF_INET, SOCK_STREAM, 0);
            if (_sock < 0)
            {
                logMessage(FATAL, "create socket error");
                exit(SOCKET_ERR);
            }
            logMessage(NORMAL, "create socket success");
            // 绑定:
            struct sockaddr_in local;
            local.sin_family = AF_INET;
            local.sin_port = htons(_port);
            local.sin_addr.s_addr = INADDR_ANY;
            if (bind(_sock, (struct sockaddr *)&local, sizeof(local)) < 0)
            {
                logMessage(FATAL, "bind socket error");
                exit(BIND_ERR);
            }
            logMessage(NORMAL, "bind socket success");
            // 设置sock为监听状态:
            if (listen(_sock, gback) < 0)
            {
                logMessage(FATAL, "listen socket error");
                exit(LISTEN_ERR);
            }
            logMessage(NORMAL, "listen socket success");
        }
        void start()
        {
            for (;;)
            {
                // 建立连接:
                struct sockaddr_in peer;
                socklen_t len = sizeof(peer);
                int sock = accept(_sock, (struct sockaddr *)&peer, &len); 
                if (sock < 0)
                {
                    logMessage(ERROR, "accept error, next");
                    continue;
                }
                logMessage(NORMAL, "accept a new link success");
                std::cout << "sock: " << sock << std::endl;
                //未来通信全部用sock,面向字节流的,后续全部都是文件操作:
                serviceIO(sock);
                close(sock);
            }
        }
        void serviceIO(int sock)
        {
            char buffer[1024];
            while(true)
            {
                ssize_t n = read(sock,buffer,sizeof(buffer)-1);
                if(n > 0)
                {
                    buffer[n] = 0;
                    cout << "recvice message: " << buffer << endl;
                    string outbuffer = buffer;
                    outbuffer += "[server echo]";
                    write(sock,outbuffer.c_str(),outbuffer.size());
                }
                else if(n == 0)
                {
                    // 代表client退出
                    logMessage(NORMAL, "client quit, me too!");
                    break;
                }
            }
        }
        ~TcpServer()
        {}
    private:
        int _sock;
        uint16_t _port;
    };
}

tcpServer.cc:启动服务器

#include"tcpServer.hpp"
#include<memory>
using namespace server;
static void Usage(string proc)
{
    cout << "\nUsage:\n\t" << proc << " local_port\n\n";
}
int main(int argc,char* argv[])
{
    if(argc != 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port = atoi(argv[1]);
    unique_ptr<TcpServer> tcs(new TcpServer(port));
    tcs->InitServer();
    tcs->start();
    return 0;
}

3.编写客户端

tcpClient.hpp

#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

namespace client
{
    using namespace std;
    class TcpClient
    {
    public:
        TcpClient(const string& serverip,const uint16_t port)
        :_serverip(serverip),_port(port),_sock(-1)
        {}
        void InitClient()
        {
            _sock = socket(AF_INET,SOCK_STREAM,0);
            if(_sock < 0)
            {
                cerr << "create sock fail" << endl;
                exit(-1);
            }
        }
        void start()
        {
            //建立连接:
            struct sockaddr_in server;
            server.sin_family = AF_INET;
            server.sin_port = htons(_port);
            server.sin_addr.s_addr = inet_addr(_serverip.c_str());
            if(connect(_sock,(struct sockaddr*)&server,sizeof(server)) != 0)
            {
                cerr << "connect fail" << endl;
            }
            else
            {
                string message;
                while(true)
                {
                    cout << "Please Enter: ";
                    getline(cin,message);
                    write(_sock,message.c_str(),message.size());
                    char buffer[1024];
                    int n = read(_sock,buffer,sizeof(buffer)-1);
                    if(n > 0)
                    {
                        buffer[n] = 0;
                        cout << "Server回复: " << buffer << endl;
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }
        ~TcpClient()
        {
            if(_sock >= 0)
                close(_sock);
        }
    private:
        string _serverip;
        uint16_t _port;
        int _sock;
    };
} // namespace client

tcpClient.cc:启动客户端

#include"tcpClient.hpp"
#include<memory>
using namespace client;
static void Usage(string proc)
{
    cout << "\nUsage:\n\t" << proc << " serverip serverport\n\n";
}
int main(int argc,char* argv[])
{
    if(argc != 3)
    {
        Usage(argv[0]);
        exit(-1);
    }
    uint16_t port = atoi(argv[2]);
    string ip = argv[1];
    unique_ptr<TcpClient> tcc(new TcpClient(ip,port));
    tcc->InitClient();
    tcc->start();
    return 0;
}

4.编译链接

makefile:

.PHONY:all
all:tcpServer tcpClient
tcpServer:tcpServer.cc
	g++ -o $@ $^ -std=c++11
tcpClient:tcpClient.cc
	g++ -o $@ $^ -std=c++11
.PHONY:clean
clean:
	rm tcpServer tcpClient

5.测试

 如图所示,服务端和客户端可以完成正常的数据通信了。

6.总结

        TCP协议和UDP协议在数据通信的实现中,除了一些接口使用的不同之外,其实并没有太大的不同,在之前说的UDP是面向数据报的而TCP是面向字节流的,这些特性又是如何体现的呢?关于这个问题,博主将在后面的文章中会为大家继续进行介绍。不要错过哦!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TCP服务器—实现数据通信 的相关文章

  • Metasploit安装及使用教程(非常详细)从零基础入门到精通,看完这一篇就够了。

    通过本篇文章 我们将会学习以下内容 1 在Windows上安装Metasploit 2 在Linux和MacOS上安装Metasploit 3 在Kali Linux中使用 Metasploit 4 升级Kali Linux 5 使用虚拟化
  • Kali Linux 安全渗透核心总结,444页核心知识点

    就像IT人离不开Linux系统一样 网安人也离不开Kali Linux 作为攻击性防御和渗透测试的代名词 越来越多的人开始学习Kali 如果你也对kali感兴趣 又想深入了解这方面内容 不妨收藏一下这份Kali Linux安全渗透教程 共4
  • 在阿里云ECS云服务器上部署和使用开源的应用程序容器引擎Docker

    Docker 是一个开源的应用程序容器引擎 具有可移植性 可扩展性 高安全性和可管理性等优势 它允许开发人员将应用程序和依赖项打包到可移植容器中 从而在 Linux 机器上高效构建 部署和管理应用程序 阿里云提供Docker镜像仓库 用于快
  • 第二节课内容学习

    监听远程端口 并映射到本地 先配置ssh的公私钥非对称加密 假设远程开放的端口为33090 在本地计算机终端执行 ssh CNg L 6006 127 0 0 1 6006 root ssh intern ai org cn p 33090
  • 一个网工(网络工程师)七年的职业血泪史....

    前言 一个工作了七年的老网工 上家公司待了五年 现在这家公司也快三年了 分享一些我自己学习网络安全路上的一些经历 也算是帮大家少走些弯路 一 如何学习网络安全 1 不要试图以编程为基础去学习网络安全 不要以编程为基础再开始学习网络安全 一般
  • 虚拟主机操作系统 Windows、Linux

    操作系统将直接影响服务器的性能 安全性和可用性 因此确保选择合适的操作系统对于成功运行您的网站或应用程序至关重要 以下是一些考虑因素 可帮助您选择适合您需求的虚拟主机操作系统 1 熟悉度和技术支持 如何选择操作系统应该考虑您的经验水平和熟悉
  • DreadHunger恐惧饥荒海上狼人杀服务器搭建架设教程windows系统

    DreadHunger 恐惧饥荒海上狼人杀服务器搭建架设教程windows系统 大家好我是艾西 在11月底我有发文 DreadHunger 恐惧饥荒海上狼人杀官方停服的消息 当时在官方的公告模版中公布了在2024年一月一日会将服务端公开让喜
  • 网络空间安全女生就业,怎么学?

    我实验室的学长们基本都是以红队和复现为主 如果学校好点可能还有更多的选择 如果想在这个方向深入下去 推荐流程是先打两年CTF 把大概的技术方向摸一摸 大一的话 如果学校还不错 那就优先建议打好基础 包括C语言 Python一类 建议把CTF
  • Linux 系统日志及其归档

    主要记录Linux 系统需要关注的日志文件 以及日志归档服务 rsyslogd 系统日志服务 rsyslogd 日志服务 rsyslogd reliable and extended syslogd 可靠 可扩展的系统日志服务 Rsyslo
  • CTF之逆向入门

    逆向工程 Reverse Engineering 又称反向工程 是一种技术过程 即对一项目标产品进行逆向分析及研究 从而演绎并得出该产品的处理流程 组织结构 功能性能规格等设计要素 以制作出功能相近 但又不完全一样的产品 逆向工程源于商业及
  • 如何解决Mybatis-plus与Mybatis不兼容的问题:An attempt was made to call a method that does not exist. The attempt

    博主猫头虎的技术世界 欢迎来到 猫头虎的博客 探索技术的无限可能 专栏链接 精选专栏 面试题大全 面试准备的宝典 IDEA开发秘籍 提升你的IDEA技能 100天精通Golang Go语言学习之旅 领域矩阵 猫头虎技术领域矩阵 深入探索各技
  • WEB前端常见受攻击方式及解决办法总结

    一个网址建立后 如果不注意安全问题 就很容易被人攻击 下面讨论一下集中漏洞情况和放置攻击的方法 一 SQL注入 所谓的SQL注入 就是通过把SQL命令插入到web表单提交或输入域名或页面请求的查询字符串 最终达到欺骗服务器执行恶意的SQL命
  • 用户数据中的幸存者偏差

    幸存者偏差 Survivorship bias 是一种常见的逻辑谬误 意思是没有考虑到筛选的过程 忽略了被筛选掉的关键信息 只看到经过筛选后而产生的结果 先讲个故事 二战时 无奈德国空防强大 盟军战机损毁严重 于是军方便找来科学家统计飞机受
  • 白帽子如何快速挖到人生的第一个漏洞 | 购物站点挖掘商城漏洞

    本文针对人群 很多朋友们接触安全都是通过书籍 网上流传的PDF 亦或是通过论坛里的文章 但可能经过了这样一段时间的学习 了解了一些常见漏洞的原理之后 对于漏洞挖掘还不是很清楚 甚至不明白如何下手 可能你通过 sql labs 初步掌握了sq
  • Jmeter 性能-并发量计算

    并发概念 指网站在同一时间访问的人数 人数越大瞬间带宽要求更高 服务器并发量分为 业务并发用户数 最大并发访问数 系统用户数 同时在线用户数 估算业务并发量的公式 C nL T C C 3 C的平方根 说明 C是平均的业务并发用户数 n是l
  • 搞懂 三次握手四次挥手

    计算机网络体系结构 在学习TCP 三次握手四次挥手之前 让我们先来看下计算机网络分层 主要分为OSI模型和TCP IP模型 OSI模型比较复杂且学术化 所以我们实际使用的TCP IP模型 以连接Mysql服务器为例理解这五层 应用层 应用层
  • 内网安全:隧道技术详解

    目录 隧道技术 反向连接技术 反向连接实验所用网络拓扑图及说明 网络说明 防火墙限制说明 实验前提说明 实战一 CS反向连接上线 拿下Win2008 一 使用转发代理上线创建监听器 二 上传后门执行上线 隧道技术 SMB协议 SMB协议介绍
  • 光波导结构

    摘要 增强现实和混合现实 AR MR 领域的新应用引起了人们对带有光栅区域的光波导系统的越来越多的关注 这些光波导系统用于输入和输出耦合以及扩瞳目的 VirtualLab Fusion为这类系统的仿真和设计提供了几个强大的工具 其中一个是具
  • 网工内推 | 上市公司同程、科达,五险一金,年终奖,最高12k*15薪

    01 同程旅行 招聘岗位 网络工程师 职责描述 1 负责职场 门店网络规划 建设 维护 2 负责网络安全及访问控制 上网行为管理和VPN设备的日常运维 3 负责内部相关网络自动化和系统化建设 4 优化与提升网络运行质量 制定应急预案 人员培
  • 网络安全行业热门认证证书合集

    网络安全认证证书 就和学历一样是敲门砖 拿到了可以用不到 但不能没有 技术大牛可以没有证书 但普通人不能没有 1 初级入门 就像学历在职场上展示一个人的基本素养一样 网络安全认证证书可以展示一个人在网络安全领域具备的基本知识和技能 它为初学

随机推荐

  • (六)Kubernetes - 手动部署(二进制方式安装)

    Kubernetes 手动部署 5 1 部署Nginx Keepalived高可用负载均衡器 1 1 安装软件包 Master1 Master2 1 2 Nginx配置文件 主备相同 1 3 keepalived配置文件 Master1 1
  • mysql jpa 不要自动建表,如何让Hibernate在与JPA一起使用时自动在数据库中创建表?...

    I am new to JPA And for now I am trying to understand standard examples I was reading online and saw a few stackoverflow
  • vue面试题汇总

    HTML篇 CSS篇 JS篇 TypeScript篇 React篇 微信小程序篇 前端面试题汇总大全 含答案超详细 HTML JS CSS汇总篇 持续更新 前端面试题汇总大全二 含答案超详细 Vue TypeScript React 微信小
  • pytorch---之item()

    torch Tensor item 坑 注意只能是一个值 适合返回loss acc
  • 设计模式概念学习

    文章目录 创建类型 单例模式 饿汉 懒汉 openbmc项目实际应用 工厂方法 简单工厂方法 openbmc项目实际应用 抽象工厂 以下为学习时对各种设计模式的简单理解 还没有深入学习和实际应用 推荐1个 很棒的网站学习设计模式 每个模式都
  • 01-windows下python爬取网页上的图片

    1 首先下载python 安装环境 pycharm anaconda的下载与安装 移步各个主页下载 一键式安装 pycharm http www jetbrains com pycharm anaconda https www anacon
  • 什么是算子?

    什么是算子 在知道什么是算子之前我们还需要知道一些其他的相关概念 大概来说 算子是一个函数空间到函数空间上的映射O X X 广义上的算子可以推广到任何空间 如内积空间等 映射 从一个拓扑空间到另一个拓扑空间的对应关系 对于每一个x 都有唯一
  • 【应用层2】Http协议

    一 简介 Http 即超文本传输协议 一种建立在 TCP 上的无状态连接 属于应用层协议 http传输的内容都是明文的 不安全的 Http 协议用于客户端与服务器端之间的通信 它规定了客户端与服务端之间的通信格式 包括请求和响应的格式 Ht
  • Springboot中配置activeMQ持久化

    一 activeMQ数据库持久化配置 ActiveMQ持久化的三种方式 我们采用数据库的方式来进行持久化 1 Memory 消息存储 基于内存的消息存储 2 基于日志消息存储方式 KahaDB是ActiveMQ的默认日志存储方式 它提供了容
  • MYSQL刷新字段:“指定字符”+年月日+三位流水号

    项目场景 项目场景 生成编号 指定字符 年月日 三位流水号 需求阐述 已经写完了生成流水号的代码 但是之前的数据并没有此类编码 所以需要把数据库新建的编码字段进行刷新 刷新数据的逻辑 根据指定字符 LSH 数据的创建时间 三位流水号进行拼接
  • 解决mysqld服务启动失败

    原因如下 1 进程占用 首先查看下mysql进程 ps aux grep mysql 有进程号占用了 kill 这个进程号 再重启服务 2 所有者和所属组为mysql 查看 usr local MySQL data mysqld pid所有
  • android功能代码--Android报表控件achartengine介绍(二)

    Android报achartengine再详细的介绍可以查看 http blog csdn net lk blog article details 7642751 在achartengine中两种创建报表的方式 1 是在Activity中直
  • ARP - Address Resolution Protocol, 地址解析协议

    1 概述 1 1 作用 ARP Address Resolution Protocol 地址解析协议 将IP 地址解析为以太网MAC 地址的协议 在局域网中 当主机或其它网络设备有数据要发送给另一个主机或设备时 它必须知道对方的网络层地址
  • 特定场景小众领域数据集之——焊缝质量检测数据集

    写这篇文章最大的初衷就是最近频繁的有很多人私信问我相关的数据集的问题 基本上都是从我前面的目标检测专栏里面的这篇文章过来的 感兴趣的话可以看下 轻量级模型YOLOv5 Lite基于自己的数据集 焊接质量检测 从零构建模型超详细教程 保姆级的
  • 例说hg(六)———— hg branch 创建分支

    开篇 branch 分支 應該也是 Hg 最重要的技能之一 在一個多人專案的開發過程中我們有時候要開發新功能 有時候是要修正某個Bug 有時候想要測試某個特異功能能不能 work 這時候我們通常都會從主 branch 再開出一條新的 bra
  • 小白的成长轨迹(二):披荆斩棘,未来可期

    大家好 我是孤焰 一名双非本科的大四学生 又是一年的1024 我坚持撰写博客已经为期一年 很感谢大家一直以来的支持 在这一年期间这位名为 孤焰 的少年又有哪些成长呢 下面便请细听分说 希望这些成长经历可以对正在看这篇文章的小可爱们有一些帮助
  • 点击echarts柱状图动态改变数据项颜色样式

    首先附上参考文章连接 https blog csdn net weixin 42870683 article details 103528254添加链接描述 今天来实现点击echarts柱状图 动态改变柱状图数据项颜色样式的案例 只要认真做
  • 向日葵的windows账号名

    向日葵的windows账号名
  • Windows11安装WSL2.0

    写这篇文章主要是记录下自己安装时的步骤 因为在网上找的一些文章无法正常安装 我安装wsl是用于在windows上运行ubuntu20 04 一 WSL2 0安装 1 启用适用于 Linux 的 Windows 子系统 2种方式第一种方式是图
  • TCP服务器—实现数据通信

    目录 前言 1 接口介绍 2 编写服务器 3 编写客户端 4 编译链接 5 测试 6 总结 前言 今天我们要介绍的是使用TCP协议实现数据通信 相比于之前写的UDP服务器实现数据信 在主体逻辑上并没有差别 客户端向服务器发送信息 服务器接受