socket编程实现TCP通信

socket编程实现TCP通信

tcp_client.cc

#include <iostream>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <unistd.h>
#include <cerrno>
#include "log.hpp"
#define SIZE 1024
uint16_t serverport;
std::string serverip;
void *tcpSend(void *args)
{
    int sock = *(int *)args;

    std::string message;
    while (true)
    {
        std::cerr << "请输入你的信息# ";
        std::getline(std::cin, message);
        send(sock, message.c_str(), message.size(), 0);
    }
}

void *tcpRecv(void *args)
{
    int sock = *(int *)args;
    char buff[1024];
    while (true)
    {
        ssize_t s = recv(sock, buff, sizeof(buff) - 1, 0);
        if (s > 0)
        {
            buff[s] = '\0';
            printf("%s\n", buff);
            fflush(stdout);
        }
    }
}
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        std::cout << "Usage: " << argv[0] << " ip port" << std::endl;
        exit(1);
    }
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0)
    {
        std::cerr << "FATAL " << errno << ":" << strerror(errno);
        exit(2);
    }

    serverport = atoi(argv[2]);
    serverip = argv[1];

    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)) == -1) {
        printf("连接失败 [%d:%s]\n",errno,strerror(errno));
        close(sock);
        exit(1);
    }
    LogMessage(NORMAL,"connect success");

    pthread_t t1, t2;
    pthread_create(&t1, nullptr, tcpSend, (void *)&sock);
    pthread_create(&t2, nullptr, tcpRecv, (void *)&sock);

    pthread_join(t1, nullptr);
    pthread_join(t2, nullptr);

    close(sock);
    return 0;
}

tcp_server.cc

#include "tcp_server.hpp"
int main(int argc,char* argv[])
{
    if(argc != 2)
    {
        std::cout<<"Usage: "<<argv[0]<<" port"<<std::endl;
        exit(1);
    }
    uint16_t port = atoi(argv[1]);
    TcpServer* svr = new TcpServer(port);
    svr->initServer();
    svr->start();
    delete svr;
    return 0;
}

tcp_server.hpp

#ifndef UDP_SERVER_HPP
#define UDP_SERVER_HPP

#include <iostream>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unordered_map>
#include <unistd.h>
#include <signal.h>
#include <wait.h>
#include "log.hpp"

#define SIZE 1024

static void service(int sock, std::string &client_ip, uint16_t &client_port)
{
    char buff[1024];
    while (true)
    {
        ssize_t s = read(sock, buff, sizeof(buff) - 1);
        if (s > 0)
        {
            buff[s] = '\0';
            printf("[%s:%d]# %s\n", client_ip.c_str(), client_port, buff);
        }
        else if (s == 0)
        {
            LogMessage(NORMAL, "[%s:%d] shutdown, me too!", client_ip.c_str(), client_port);
            break;
        }
        else
        {
            LogMessage(ERROR, "read socket error, %d:%s", errno, strerror(errno));
            break;
        }
        write(sock, buff, strlen(buff));
    }
}
struct ThreadData
{
    int _sock;
    std::string _ip;
    uint16_t _port;
};
class TcpServer
{
private:
    const int gbacklog = 20;

public:
    static void* threadRoutine(void* args)
    {
        pthread_detach(pthread_self());
        ThreadData* td = (ThreadData*)args;
        service(td->_sock, td->_ip, td->_port);
        delete td;
        return nullptr;
    }
    TcpServer(uint16_t port, std::string ip = "0.0.0.0")
        : _port(port), _listensock(-1),_ip(ip)
    {
    }
    void initServer()
    {
        // 创建套接字
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock < 0)
        {
            LogMessage(FATAL, "socket error, %d:%s", errno, strerror(errno));
            exit(2);
        }
        // 绑定
        struct sockaddr_in local;
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = inet_addr(_ip.c_str());
        if (bind(_listensock, (struct sockaddr *)&local, sizeof(local)) < 0)
        {
            LogMessage(FATAL, "bind error, %d:%s", errno, strerror(errno));
            exit(3);
        }
        // 建立连接(监听)
        if (listen(_listensock, gbacklog) < 0)
        {
            LogMessage(FATAL, "listen error, %d:%s", errno, strerror(errno));
            exit(4);
        }
        LogMessage(NORMAL, "init TCP server success, listensock: %d", _listensock);
    }
    void start()
    {
        signal(SIGCHLD,SIG_IGN);//不理会子进程 v2.1
        while (true)
        {
            // 获取连接
            struct sockaddr_in src;
            socklen_t len = sizeof(src);
            int servicesock = accept(_listensock, (struct sockaddr *)&src, &len);
            std::cout<<servicesock<<std::endl;
            if (servicesock < 0)
            {
                LogMessage(ERROR, "accept error, %d:%s", errno, strerror(errno));
                continue;
            }
            uint16_t client_port = ntohs(src.sin_port);
            std::string client_ip = inet_ntoa(src.sin_addr);
            LogMessage(NORMAL, "link success, [%s:%d]", client_ip.c_str(), client_port);
            // 获取连接成功,开始通信服务
            // v1 单进程循环
            //service(servicesock, client_ip, client_port);

            //v2.0 多进程
            // pid_t id = fork();
            // if(id == 0)
            // {
            //     close(_listensock);
            //     service(servicesock, client_ip, client_port);
            //     exit(0);
            // }
            // close(servicesock);

            //v2.1 多进程
            // pid_t id = fork();
            // if(id == 0)
            // {
            //     close(_listensock);
            //     if(fork() > 0) exit(0);
            //     service(servicesock, client_ip, client_port);
            // }
            // waitpid(id,nullptr,0);
            // close(servicesock);

            //v3 多线程
            ThreadData* td = new ThreadData;
            td->_sock = servicesock;
            td->_ip = client_ip;
            td->_port = client_port;
            pthread_t tid;
            pthread_create(&tid,nullptr,threadRoutine,(void*)td);
            close(servicesock);


        }
    }

private:
    uint16_t _port;
    std::string _ip;
    int _listensock;
};
#endif

log.hpp

#pragma once
#include<iostream>
#include<cstdio>
#include<cstdarg>
#include<ctime>
#include<string>

#define DEBUG   0
#define NORMAL  1
#define WARNING 2
#define ERROR   3
#define FATAL   4
const char* gLevelMap[]={"DEBUG","NORMAL","WARNING","ERROR","FATAL"};

void LogMessage(int level,const char* format,...)
{
    char stdBuffer[1024] = {'\0'};
    time_t timestamp = time(nullptr);
    snprintf(stdBuffer,sizeof stdBuffer,"[%s] [%ld]",gLevelMap[level],timestamp);

    char logBuffer[1024] = {'\0'};;
    va_list args;
    va_start(args,format);
    vsnprintf(logBuffer,sizeof logBuffer,format,args);
    va_end(args);
    printf("%s%s\n",stdBuffer,logBuffer);
}

makefile

.PHONY:add
all:tcp_client tcp_server
tcp_client:tcp_client.cc
	g++ -o $@ $^ -std=c++11 -l pthread
tcp_server:tcp_server.cc
	g++ -o $@ $^ -std=c++11 -l pthread
.PHONY:clean
clean:
	rm -f tcp_client tcp_server

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

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

相关文章

算法一:数字 - 两数之和

给定一个整数数组 nums 和一个目标值 target&#xff0c;请你在该数组中找出和为目标值的那 两个 整数&#xff0c;并返回他们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素不能使用两遍。 来源&#xff1a;力扣(LeetCode) 链接&#xf…

政安晨:【Keras机器学习示例演绎】(一)—— 利用类 U-Net 架构进行图像分割

目录 下载数据 准备输入图像的路径和目标分割掩码 一幅输入图像和相应的分割掩码是什么样子的&#xff1f; 准备数据集&#xff0c;以加载和矢量化成批数据 准备 U-Net Xception 风格模型 预留验证分割 训练模型 可视化预测 政安晨的个人主页&#xff1a;政安晨 欢迎 &…

4.18学习总结

多线程补充 等待唤醒机制 现在有两条线程在运行&#xff0c;其中一条线程可以创造一个特殊的数据供另一条线程使用&#xff0c;但这个数据的创建也有要求&#xff1a;在同一时间只允许有一个这样的特殊数据&#xff0c;那么我们要怎样去完成呢&#xff1f;如果用普通的多线程…

FTP客户端Transmit 5 for Mac中文激活版

Transmit 5是一款功能强大的Mac FTP客户端软件&#xff0c;它由Panic公司开发&#xff0c;为用户提供简单、高效的文件传输体验。 Transmit 5 for Mac中文激活版下载 Transmit 5支持多种传输协议&#xff0c;如FTP、SFTP、WebDAV和Amazon S3等&#xff0c;满足用户不同的文件传…

eCongnition 获取特征(shp)

目录 1、加载数据和分割的shp文件 2、将专题(导入的shp)转换为对象 3、导出特征 1、加载数据和分割的shp文件 我们加载数据&#xff0c;在第二个框&#xff08;Thematic La..&#xff09;里加载矢量shp 导入的.shp文件称为专题层(Thematic Layer), 显示方式如下所示&#x…

深入探索:Facebook如何重塑社交互动

在当代社会中&#xff0c;社交互动已成为日常生活的核心组成部分。而在众多的社交媒体平台中&#xff0c;Facebook凭借其卓越的用户基础和创新的功能&#xff0c;已经成为了全球最大的社交媒体平台。本文将深入探讨Facebook如何通过其独特的特性和功能&#xff0c;重塑了人们的…

Python 字符串 Base64

因消息传输的需要&#xff0c;我们需要对大量文本的字符串进行一下 Base64 转换。 这样的好处是因为在传输的字符串中可能有存在一些特殊字符&#xff0c;这些特殊在经过网络传输的时候会出现编码的问题&#xff0c;并且会影响传输稳定性。 使用 Base64 可以避免这个问题。 方…

数据库--Sqlite3

1、思维导图 2sqlite3在linux中是实现数据的增删&#xff0c;改 #include<myhead.h> int main(int argc, const char *argv[]) { //1、定义一个数据库句柄指针 sqlite3* ppDb NULL; //2、创建或打开数据库 if(sqlite3_open("./mydb…

深入解析Apache Hadoop YARN:工作原理与核心组件

什么是YARN&#xff1f; YARN&#xff08;Yet Another Resource Negotiator&#xff09;是Apache Hadoop生态系统中的一个重要组件&#xff0c;用于资源管理和作业调度。它是Hadoop 2.x版本中的一个关键特性&#xff0c;取代了旧版本中的JobTracker和TaskTracker。YARN的设计目…

ElasticSearch实战之项目搜索高亮

文章目录 1. 前情配置2、数据操作2.1 操作API2.2 数据入库 3. 高亮搜索3.1 方法封装3.2 高亮搜索 1. 前情配置 为满足ElasticSearch可在项目中实现搜索高亮&#xff0c;我们需要先做一些前情配置 导入ElasticSearch依赖 <dependency><groupId>org.springframewor…

【Flutter】多语言方案一:flutter_localizations 与 GetX 配合版

系列文章目录 多语言方案&#xff1a;flutter_localizations 与 GetX 配合版&#xff0c;好处&#xff1a;命令行生成多语言字符串的引用常量类&#xff0c;缺点&#xff1a;切换语言以后&#xff0c;主界面需要手动触发setState&#xff0c;重绘将最新的Locale数据设置给GetM…

【Leetcode每日一题】 分治 - 排序数组(难度⭐⭐)(60)

1. 题目解析 题目链接&#xff1a;912. 排序数组 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 算法思路&#xff1a; 快速排序作为一种经典的排序算法&#xff0c;其核心思想在于通过“分而治之”的策略&#xff…

Idea修改【Help->Edit Custom VM Options...】后,导致idea无法正常启动的解决方法

一、错误场景: 二、解决方法&#xff1a; 修改文件路径&#xff1a;C:\Users\tianjm&#xff08;写自己的用户名&#xff09;\AppData\Roaming\JetBrains\IdeaIC2024.1&#xff08;选自己安装的版本&#xff09;

Linux 网络编程项目--简易ftp

主要代码 config.h #define LS 0 #define GET 1 #define PWD 2#define IFGO 3#define LCD 4 #define LLS 5 #define CD 6 #define PUT 7#define QUIT 8 #define DOFILE 9struct Msg {int type;char data[1024];char secondBuf[128]; }; 服务器: #i…

传统零售行业如何做数字化转型?

传统零售行业的数字化转型是一个系统性的过程&#xff0c;涉及到企业的多个方面。以下是一些关键步骤和策略&#xff0c;帮助传统零售企业实现数字化转型&#xff1a; 1、明确转型目标和战略 首先&#xff0c;企业需要明确数字化转型的目标和战略。包括确定企业的核心竞争力、…

Java内存模型和 JVM 内存运行时

文章目录 前言一、什么是Java 的内存模型&#xff1f;二、什么是 JVM 的运行时数据区Java8 之前和之后的区别JVM 内存模型JVM 内存区域JVM 内存垃圾回收JVM如何判断哪些对象不在存活&#xff1f;JVM运行过程中如何判断哪些对象是垃圾&#xff1f; JVM 垃圾回收Java8 中的 jvm如…

.rmallox勒索病毒来袭:如何守护您的数据安全?

引言&#xff1a; 随着信息技术的飞速发展&#xff0c;网络安全问题日益凸显&#xff0c;其中勒索病毒更是成为了网络安全领域的一大难题。.rmallox勒索病毒作为一种典型的恶意软件&#xff0c;通过加密受害者文件并勒索赎金的方式&#xff0c;给企业和个人带来了巨大的经济损…

指纹浏览器如何高效帮助TikTok账号矩阵搭建?

TikTok的账号矩阵&#xff0c;可能听起来还比较陌生&#xff0c;但随着TikTok业务已经成为吃手可热的跨境业务&#xff0c;TikTok多账号矩阵已成为流行策略。但它有什么优点呢&#xff1f;操作多个帐户会导致被禁止吗&#xff1f;如何有效地建立账户矩阵开展业务&#xff1f;这…

爬虫 | 基于 requests 实现加密 POST 请求发送与身份验证

Hi&#xff0c;大家好&#xff0c;我是半亩花海。本项目旨在实现一个简单的 Python 脚本&#xff0c;用于向指定的 URL 发送 POST 请求&#xff0c;并通过特定的加密算法生成请求头中的签名信息。这个脚本的背后是与某个特定的网络服务交互&#xff0c;发送特定格式的 JSON 数据…

深入理解MySQL中的UPDATE JOIN语句

在MySQL数据库中&#xff0c;UPDATE语句用于修改表中现有的记录。有时&#xff0c;我们需要根据另一个相关联表中的条件来更新表中的数据。这时就需要使用UPDATE JOIN语句。最近我们遇到了这样的需求&#xff1a;我们有一张历史记录表&#xff0c;其中一个字段记录了用,连接的多…
最新文章