【计算机网络】TCP网络程序

news2024/11/14 13:55:18

一、服务端

1.tcpServer.hpp

#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>

enum
{
    USAGE_ERR = 1,
    SOCKET_ERR,
    BIND_ERR,
    LISTEN_ERR
};

static const uint16_t gport = 8080;
static const int gbacklog = 5;
class TcpServer;

class ThreadData
{
public:
    ThreadData(TcpServer *self, int sock)
        : _self(self), _sock(sock)
    {}

public:
    TcpServer *_self;
    int _sock;
};

class TcpServer
{
public:
    // 构造函数
    TcpServer(const uint16_t &port = gport)
        : _listensock(-1), _port(port)
    {}
    // 析构函数
    ~TcpServer() {}
    // 初始化服务器
    void initServer()
    // 启动服务器
    void start()

private:
    int _listensock; // 不是用来进行数据通信的,他是用来监听链接到来,获取新链接的!
    uint16_t _port;  // 端口号
};

(1)initServer()

void initServer()
{
    // 1.创建socket文件套接字对象
    _listensock = socket(AF_INET, SOCK_STREAM, 0);
    if (_listensock < 0)
    {
        logMessage(FATAL, "create socket error");
        exit(SOCKET_ERR);
    }
    logMessage(NORMAL, "create socket success:%d", _listensock); // ? 后面可能会加东西

    // 2.bind绑定自己的网络信息
    struct sockaddr_in local;
    memset(&local, 0, sizeof(local));
    local.sin_family = AF_INET;
    local.sin_port = htons(_port);
    local.sin_addr.s_addr = INADDR_ANY;
    if (bind(_listensock, (struct sockaddr *)&local, sizeof(local)) < 0)
    {
        logMessage(FATAL, "bind socket error");
        exit(BIND_ERR);
    }
    logMessage(NORMAL, "bind socket success");

    // 3.设置socket 为监听状态
    if (listen(_listensock, gbacklog) < 0) // listen第二个参数以后在讲
    {
        logMessage(FATAL, "listen socket error");
        exit(LISTEN_ERR);
    }
    logMessage(NORMAL, "listen socket success");
}

(2)start()

void start()
{
    for (;;)
    {
        // 4.server 获取新链接
        // sock 才是和client进行通信的fd
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        int sock = accept(_listensock, (struct sockaddr *)&peer, &len);
        if (sock < 0)
        {
            logMessage(ERROR, "accept error, next");
            continue;
        }
        logMessage(NORMAL, "accept a new link success, get new sock:%d", sock);

        // 5.这里就是一个sock,未来通信我们就用这个sock,面向字节流的,后续全部都是文件操作!
        serviceIO(sock);
        close(sock); // 对一个已经使用完毕的sock,我们要关闭这个sock,要不然会导致,文件描述符泄露
    }
}

2.tcpServer.cpp

#include "tcpServer.hpp"
#include <memory>

using namespace std;

// 使用手册
static void Usage(string proc)
{
    cout << "\nUsage:\n\t" << proc << " local_port\n\n";
}

// ./tcpServer local_port
int main(int argc, char *argv[])
{
    if(argc != 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port = atoi(argv[1]);

    // tcp服务器的调用逻辑
    unique_ptr<TcpServer> tsvr(new TcpServer(port));
    tsvr->initServer();
    tsvr->start();

    return 0;
}

二、客户端

1.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>

#define NUM 1024

class TcpClient
{
public:
    // 构造函数
    TcpClient(const std::string &serverip, const uint16_t &serverport)
    :_sock(-1), _serverip(serverip), _serverport(serverport)
    {}
    // 析构函数
    ~TcpClient()
    {
        if(_sock >= 0)
            close(_sock);
    }
    // 初始化客户端
    void initClient()
    // 启动客户端
    void start()

private:
    int _sock;
    std::string _serverip;
    uint16_t _serverport;
};

(1)initClient()

void initClient()
{
    // 1.创建socket
    _sock = socket(AF_INET, SOCK_STREAM, 0);
    if (_sock < 0)
    {
        std::cerr << "socket create error" << std::endl;
        exit(2);
    }

    // 2.tcp的客户端要不要bind?要的! 但是要不要显示的bind?不要!尤其这里client port要让OS自己随机指定!
    // 3.要不要listen?不要!
    // 4.要不要accept?不要!
}

(2)start()

void start()
{
    // 5.要发起连接!
    struct sockaddr_in server;
    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(_serverport);
    server.sin_addr.s_addr = inet_addr(_serverip.c_str());

    if (connect(_sock, (struct sockaddr *)&server, sizeof(server)) != 0)
    {
        std::cerr << "socket connet error" << std::endl;
    }
    else
    {
        // 成功连接
        std::string msg;
        while (true)
        {
            std::cout << "Enter# ";
            std::getline(std::cin, msg);
            write(_sock, msg.c_str(), msg.size());

            char buffer[NUM];
            int n = read(_sock, buffer, sizeof(buffer) - 1);
            if (n > 0)
            {
                // 目前我们可以吧读到的数据当成字符串
                buffer[n] = 0;
                std::cout << "Server回显# " << buffer << std::endl;
            }
            else
            {
                break;
            }
        }
    }
}

2.tcpClient.cpp

#include "tcpClient.hpp"
#include <memory>

// 使用手册
static void Usage(std::string proc)
{
    std::cout << "\nUsage:\n\t" << proc << " serverip serverport\n\n";
}

// ./tcpclient serverip serverport
int main(int argc, char *argv[])
{
    if(argc != 3)
    {
        Usage(argv[0]);
        exit(1);
    }
    std::string serverip = argv[1];
    uint16_t serverport = atoi(argv[2]);

    std::unique_ptr<TcpClient> tcli(new TcpClient(serverip, serverport));
    tcli->initClient();
    tcli->start();

    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

万字长文解读深度学习——Transformer

&#x1f33a;历史文章列表&#x1f33a; 深度学习——优化算法、激活函数、归一化、正则化深度学习——权重初始化、评估指标、梯度消失和梯度爆炸深度学习——前向传播与反向传播、神经网络&#xff08;前馈神经网络与反馈神经网络&#xff09;、常见算法概要汇总万字长文解读…

Leecode热题100-35.搜索插入位置

给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 示例 1: 输入: nums [1,3,5,6], target 5 输出: 2示例 2: 输入:…

LabVIEW环境监测系统

随着环境问题的日益严重&#xff0c;环境参数的实时监测成为保障公共健康和生态平衡的重要手段。开发了一款基于LabVIEW开发的环境监测系统&#xff0c;能够对大气中的温度、湿度及二氧化硫浓度进行实时监测&#xff0c;并提供数据存储和超阈值报警功能。 系统组成 本系统由下…

7.4、实验四:RIPv2 认证和触发式更新

源文件 一、引言&#xff1a;为什么要认证和采用触发式更新&#xff1f; 1. RIP v2 认证 RIP&#xff08;Routing Information Protocol&#xff09;版本 2 添加了认证功能&#xff0c;以提高网络的安全性。认证的作用主要包括以下几点&#xff1a; 防止路由欺骗 RIP v1 是不…

人力资源招聘系统-提升招聘效率与质量的关键工具

在当今这个竞争激烈的商业环境中&#xff0c;企业要想在市场中立于不败之地&#xff0c;关键在于拥有高素质的人才队伍。然而&#xff0c;传统的招聘方式往往效率低下&#xff0c;难以精准匹配企业需求与人才特质&#xff0c;这无疑给企业的发展带来了不小的挑战。 随着科技的飞…

【Linux系统编程】第四十六弹---线程同步与生产消费模型深度解析

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、Linux线程同步 1.1、同步概念与竞态条件 1.2、条件变量 1.2.1、认识条件变量接口 1.2.2、举例子认识条件变量 1.2.3、…

UAV-VisLoc:中国11地大规模无人机视觉定位数据集

2024-05-16&#xff0c;由中科院、北京邮电大学和香港城市大学联合创建了UAV-VisLoc数据集&#xff0c;这个数据集通过收集中国11个不同地点的无人机图像和卫星地图&#xff0c;为无人机在失去全球导航卫星系统(GNSS)信号时提供精确的经纬度坐标定位&#xff0c;具有重要的实际…

el-table 行列文字悬浮超出屏幕宽度不换行的问题

修改前的效果 修改后的效果 ui框架 element-plus 在网上找了很多例子都没找到合适的 然后这个东西鼠标挪走就不显示 控制台也不好调试 看了一下El-table的源码 他这个悬浮文字用的el-prpper 包着的 所以直接改 .el-table .el-propper 设置为max-width:1000px 就可以了 吐槽一…

SystemVerilog学习笔记(十):进程/细粒度进程控制

进程 进程或线程是作为独立实体执行的任何代码片段。fork-join块创建并行运行的不同线程。在下面的图-1中&#xff0c;可以看到进程的类型和进程控制。 序号进程描述1.fork-join只有所有子线程执行完毕时&#xff0c;父线程才会执行。2.fork-join_any只有任何一个子线程执行完…

MySQL技巧之跨服务器数据查询:高级篇-先调用A数据库的MySql存储过程再复制到B数据库的表中

MySQL技巧之跨服务器数据查询&#xff1a;高级篇-先调用A数据库的MySql存储过程再复制到B数据库的表中 基础篇已经描述&#xff1a;借用微软的SQL Server ODBC 即可实现MySQL跨服务器间的数据查询。 而且还介绍了如何获得一个在MS SQL Server 可以连接指定实例的MySQL数据库的…

【数据结构】10.线索二叉树

一、线索二叉树的产生 采用先序、中序、后序三种方法遍历二叉树后都可以得到一个线性序列&#xff0c;序列上的每一个结点&#xff08;除了第一个和最后一个&#xff09;都有一个前驱和一个后继&#xff0c;但是&#xff0c;这个线性序列只是逻辑的概念&#xff0c;不是物理结…

springboot食物营养分析平台-计算机毕业设计源码75335

摘要 随着我国经济的发展,人民生活水平的提高&#xff0c;人们的饮食己由温饱型转向营养型。因此&#xff0c;营养问题日益受到重视。食物营养分析平台采用Java技术&#xff0c;Mysql数据库存储数据&#xff0c;基于Springboot框架开发。系统采用了模块化设计方法&#xff0c;根…

使用elementUI实现表格行拖拽改变顺序,无需引入外部库

前言&#xff1a; 使用vue2element UI&#xff0c;且完全使用原生的拖拽事件,无需引入外部库。 如果表格数据量较大&#xff0c;或需要更多复杂功能&#xff0c;可以考虑使用 vuedraggable库&#xff0c;提供更多配置选项和拖拽功能。 思路&#xff1a; 1. 通过el-table的ro…

开源共建 | 长安链开发常见问题及规避

长安链开源社区鼓励社区成员参与社区共建&#xff0c;参与形式包括不限于代码贡献、文章撰写、社区答疑等。腾讯云区块链王燕飞在参与长安链测试工作过程中&#xff0c;深入细致地总结了长安链实际开发应用中的常见问题及其有效的规避方法&#xff0c;相关内容多次解答社区成员…

Python - 初识Python;Python解释器下载安装;Python IDE(一)

一、初识Python Python 是一种高级编程语言&#xff0c;Python是一种面向对象的解释型计算机程序设计语言&#xff0c;Python由荷兰国家数学与计算机科学研究中心的吉多范罗苏姆&#xff08;&#xff09;Guido van Rossum吉多范罗苏姆&#xff08;&#xff09;于1989 年底发明…

Linux入门攻坚——37、Linux防火墙-iptables-3

私网地址访问公网地址的问题&#xff0c;请求时&#xff0c;目标地址是公网地址&#xff0c;可以在公网路由器中进行路由&#xff0c;但是响应报文的目的地址是私网地址&#xff0c;此时在公网路由器上就会出现问题。公网地址访问私网地址的问题&#xff0c;需要先访问一个公网…

C语言的内存函数(文章后附gitee链接,模拟实现函数)

之前我们已经讲解过了字符型数据的一类字符串函数&#xff0c; 现在我们来讨论字符型以外的数据处理。 1&#xff1a;memcpy 的使用和模拟实现 void * memcpy ( void * destination, const void * source, size_t num )&#xff1b; 注意&#xff1a; 1&#xff1a;函数memcp…

Leetcode 整数转罗马数字

这段代码的算法思想是基于罗马数字的减法规则&#xff0c;将整数转换为罗马数字的字符串表示。下面是详细的解释&#xff1a; 算法步骤&#xff1a; 定义数值和符号对应关系&#xff1a;代码中定义了两个数组&#xff1a;values 和 symbols。values 数组包含了罗马数字的数值&…

【赵渝强老师】MySQL InnoDB的段、区和页

MySQL的InnoDB存储引擎的逻辑存储结构和Oracle大致相同&#xff0c;所有数据都被逻辑地存放在一个空间中&#xff0c;我们称之为表空间&#xff08;tablespace&#xff09;。表空间又由段&#xff08;segment&#xff09;、区&#xff08;extent&#xff09;、页&#xff08;pa…

element-ui-plus给头像avatar增加头像框

template部分&#xff1a; <el-avatar shape"square" :size"50" :fit"fit":src"avatarImg"class"avatar-with-border-image"/>style部分&#xff1a; .avatar-with-border-image {position: relative;margin-top: 5px…