建立基于TCP的客户端和服务端

函数介绍: 

1.socket()

作用:创建套接字

domain:

  • AF_INET:IPv4 Internet 协议族。
  • AF_INET6:IPv6 Internet 协议族。
  • AF_UNIX:Unix 域协议族,用于在同一台主机上的进程间通信。

type:

  • SOCK_STREAM:提供序列化的、可靠的、双向连接的字节流服务,通常用于TCP连接。
  • SOCK_DGRAM:提供无连接的、不可靠的数据报服务,通常用于UDP通信。

protocol:

        这个参数指定了使用的特定协议。对于很多常见的套接字类,如 SOCK_STREAM 和 SOCK_DGRAM,这个参数可以设置为0,系统会自动选择一个默认协议。

return value:

socket() 函数调用成功时,返回一个非负整数,即新创建的套接字的文件描述符(socket descriptor)。如果调用失败,函数返回-1,并且 errno 被设置为描述错误的值。

服务端:

2.bind()

作用:将套接字(fd)和ip和port绑定起来

sockfd:

  • 要绑定的文件描述符,也就是socket的返回值

addr:

 指向 sockaddr 结构体的指针,该结构体包含了套接字的地址信息。

  • sin_family:协议家族
  • sin_port:要绑定的端口。
  • sin_addr.s_addr:要绑定的ip

 介绍以下里面的函数:

h表示host,n表示network

htons 通常用于端口号,htonl 通常用于IP地址

作用:将IPv4地址的点分十进制字符串表示转换为网络字节序的二进制值

INADDR_ANY:用于指定一个特殊的IPv4地址0.0.0.0,表示“接受任何可用的网络接口”,通常用在服务器监听上。

addrlen: 大小

return value:

成功返回0,失败返回-1并设置错误码。

3.listen()

作用:将套接字设置为监听状态可以监听链接请求

sockfd:socket()的返回值

backlog:一个大于0的整数(后续补充)

return value:成功返回0失败返回-1并设置错误码

4.accept()

 作用:接受链接请求

sockfd:socket()的返回值

addr和addrlen:输出型参数,用于存储连接客户端的地址信息。

return value:

成功返回一个新的文件描述符用于与连接的客户端进行通信。之后的read和write传入的都是accept的返回值。

失败返回-1,设置错误码。

 客户端:

2.connect()

 

作用:向服务端发起链接

sockfd:socket()的返回值

addr:要连接的服务端的地址信息

addrlen:addr的大小

return value:

成功返回0,失败返回-1并设置错误码。

代码: 

tcpServer.hpp

#pragma once
#include <iostream>
#include <string>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#include <cstdlib>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include "log.hpp"
#include "threadpool.hpp"namespace server
{enum{USAGE_ERR = 1,SOCKET_ERR,BIND_ERR,LISTEN_ERR,OPEN_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){}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){logMessage(FATAL, "listen socket error");exit(LISTEN_ERR);}logMessage(NORMAL, "listen socket success");}void start(){// 4.线程池初始化ThreadPool<Task>::getInstance()->run();logMessage(NORMAL, "Thread init success");// signal(SIGCHLD,SIG_IGN);//忽略这个信号for (;;){// 4.server获取新链接// sock,和client进行通信的fdstruct sockaddr_in peer;socklen_t len = sizeof(peer);int sock = accept(_listensock, (struct sockaddr *)&peer, &len);if (sock < 0){logMessage(ERROR, "accept error");continue;}logMessage(NORMAL, "accept a new link success,get a new sock:%d", sock);serviceIO(sock);close(sock);//对一个已经使用完毕的sock,我们必须要关闭这个sock,要不然会导致文件描述符泄漏}}// static void *threadRoutine(void *args)// {//     pthread_detach(pthread_self());//     ThreadData *td = static_cast<ThreadData *>(args);//     td->_self->serviceIO(td->_sock);//     delete td;//     close(td->_sock);//     return nullptr;// }~TcpServer() {}private:int _listensock;uint16_t _port;};
}
// 5.这里就是一个sock,未来通信我们就用这个sock,面向字节流的,后续全部都是文件操作!
//  serviceIO(sock);
//  close(sock);//对一个已经使用完毕的sock,我们必须要关闭这个sock,要不然会导致文件描述符泄漏// version2,多进程版,多线程版,线程池版
// version1,多进程版
//  pid_t id = fork();
//  if(id == 0)//child
//  {
//      close(_listensock);
//      if(fork()>0) exit(0);//关闭child,创建了一个孙子。因为child退了,孙子进程成了孤儿进程,由操作系统回收
//      serviceIO(sock);
//      close(sock);//对一个已经使用完毕的sock,我们必须要关闭这个sock,要不然会导致文件描述符泄漏
//      exit(0);
//  }
// father
//  pid_t ret = waitpid(id,nullptr,0);
//  if(ret>0)
//  {
//      std::cout<<"wait success:"<<ret<<std::endl;
//  }// version2,多进程版
//  pid_t id = fork();
//  if(id == 0)//child
//  {
//      close(_listensock);
//      serviceIO(sock);
//      close(sock);//对一个已经使用完毕的sock,我们必须要关闭这个sock,要不然会导致文件描述符泄漏
//      exit(0);
//  }
//  close(sock);// version3:多线程版
//  pthread_t tid;
//  ThreadData* td = new ThreadData(this,sock);
//  pthread_create(&tid,nullptr,threadRoutine,td);// version4:线程池
//ThreadPool<Task>::getInstance()->push(Task(sock, serviceIO));

 tcpServer.cc

#include"tcpServer.hpp"
#include<memory>
using namespace server;
using namespace std;
static void Usage(string proc)
{cout<<".\nUsage:\n\t"<<proc<<"local_port\n\n";
}
//tcp服务器,启动上和udp Server一模一样
//./tcpServer local_port
int main(int argc,char* argv[])
{if(argc!=2){Usage(argv[0]);exit(USAGE_ERR);}uint16_t port = atoi(argv[1]);unique_ptr<TcpServer> tsvr(new TcpServer(port));tsvr->initServer();tsvr->start();return 0;}

tcpClient.hpp 

#pragma once
#include <iostream>
#include<string>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<cstring>
#define NUM 1024
class TcpClient
{public:TcpClient(const std::string &serverip,const uint16_t &serverport):_sock(-1),_serverip(serverip),_serverport(serverport){}void initClient(){//1.创建socket_sock = socket(AF_INET,SOCK_STREAM,0);if(_sock < 0){std::cerr<<"socket create error"<<std::endl;exit(2);}//2.客户端不用显示的bind//3.要不要listen?没人连我啊//4.要不要accept?no//5.要什么呢?要发起链接!}void start(){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 connect error"<<std::endl;}else{std::string msg;while(1){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;}}}}~TcpClient(){if(_sock >= 0)close(_sock);//文件描述符的生命周期随进程,所以这里不写也行}
private:int _sock;std::string  _serverip;uint16_t _serverport;};

tcpClient.cc 

#include"tcpClient.hpp"
#include<memory>
using namespace std;
static void Usage(string proc)
{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);}string serverip = argv[1];uint16_t serverport = atoi(argv[2]);unique_ptr<TcpClient> tcli(new TcpClient(serverip,serverport));tcli->initClient();tcli->start();return 0;
}

Task.hpp 

#pragma once#include <iostream>
#include <string>
#include <cstdio>
#include <functional>
#include <unistd.h>
#include <string.h>
#include"log.hpp"
void serviceIO(int sock)
{char buffer[1024];while (true){ssize_t n = read(sock, buffer, sizeof(buffer) - 1);if (n > 0){// 目前我们把读到的数据当成字符串,截止目前// 为什么UDP并不符合文件特性,文件也是字节流的,UDP是数据报的,所以要用特殊函数来读buffer[n] = 0;std::cout << "recv messages:" << buffer << std::endl;write(sock, buffer, strlen(buffer)); // 多路转接}else if (n == 0){// 代表client退出logMessage(NORMAL, "client quit,me too!");break;}}close(sock);
}class Task
{using func_t = std::function<void(int)>;public:Task() {}Task(int sock, func_t func): _sock(sock), _callback(func){}void operator()(){_callback(_sock);}private:int _sock;func_t _callback;
};

log.hpp 

#pragma once
#include<iostream>
#include<string>
#include<cstdarg>
#include<ctime>
#include<unistd.h>
//cat /var/log/messages系统日志
//日志等级
#define DEBUG   0
#define NORMAL  1
#define WARNING 2
#define ERROR   3
#define FATAL   4//致命错误const char* to_levelstr(int level)
{switch(level){case DEBUG:return "DEBUG";case NORMAL:return "NORMAL";case WARNING:return "WARNING";case ERROR:return "ERROR";case FATAL:return "FATAL";}
}
// void logMessage(int level,const char* messages)
// {
//     std::cout<<messages<<std::endl;
// }
// void logMessage(DEBUG,"hello %f ,%d,%c",3.14,10,'C');
void logMessage(int level,const char* format,...)
{//[日志等级][时间戳/时间][pid][message]//暂定// va_list start;// va_start(start);// while(*p)// {//     switch(*p)//     {//         case '%'://             p++;//             if(*p == 'f') arg = va_arg(start,float);//         ...//     }// }// va_end(start);#define NUM 1024char logprefix[NUM];snprintf(logprefix,sizeof(logprefix),"[%s][%ld][pid:%d]",to_levelstr(level),(long int)time(nullptr),getpid());char logcontent[NUM];va_list arg;va_start(arg,format);vsnprintf(logcontent,sizeof(logcontent),format,arg);std::cout<<logprefix<<logcontent<<std::endl;
}

makefile 

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL语句在MySQL中如何执行

MySQL的基础架构 首先就是客户端&#xff0c;其次Server服务层&#xff0c;大多数MySQL的核心服务都在这一层&#xff0c;包括连接、分析、优化、缓存以及所有的内置函数&#xff08;时间、日期、加密函数&#xff09;&#xff0c;所有跨存储引擎功能都在这一层实现&#xff1…

轻量化特征融合 | 一种基于增强层间特征相关性的轻量级特征融合网络 | 北理工新作

论文题目&#xff1a;A Lightweight Fusion Strategy With Enhanced Interlayer Feature Correlation for Small Object Detection 论文链接&#xff1a;https://ieeexplore.ieee.org/abstract/document/10671587 giuhub&#xff1a;https://github.com/nuliweixiao/EFC 关键词…

vue2+element-ui实现多行行内表格编辑

效果图展示 当在表格中点击编辑按钮时:点击的行变成文本框且数据回显可以点击确定按钮修改数据或者取消修改回退数据: 具体实现步骤 1. 行数据定义编辑标记 行数据定义编辑标记 当在组件中获取到用于表格展示数据的方法中,针对每一行数据添加一个编辑标记 this.list.f…

docker简单私有仓库的创建

1&#xff1a;下载Registry镜像 导入镜像到本地中 [rootlocalhost ~]# docker load -i registry.tag.gz 进行检查 2&#xff1a;开启Registry registry开启的端口号为5000 [rootlocalhost ~]# docker run -d -p 5000:5000 --restartalways registry [rootlocalhost ~]# dock…

使用 GD32F470ZGT6,手写 I2C 的实现

我的代码&#xff1a;https://gitee.com/a1422749310/gd32_-official_-code I2C 具体代码位置&#xff1a;https://gitee.com/a1422749310/gd32_-official_-code/blob/master/Hardware/i2c/i2c.c 黑马 - I2C原理 官方 - IIC 协议介绍 个人学习过程中的理解&#xff0c;有错误&…

VSCode,Anaconda,JupyterNotebook

文章目录 一. 下载VSCode并安装二. 下载Anaconda并安装1. anaconda介绍2. Anaconda的包管理功能3. Anaconda的虚拟环境管理4.Jupyter Notebook5. Jupyter Notebook使用简介6. Jupyter Notebook快捷键7.Jupyter notebook的功能扩展8. Jupyter notebook和Jupyter lab的区别 三. V…

【安全研究】某黑产网站后台滲透与逆向分析

文章目录 x01. 前言x02. 分析 【&#x1f3e0;作者主页】&#xff1a;吴秋霖 【&#x1f4bc;作者介绍】&#xff1a;擅长爬虫与JS加密逆向分析&#xff01;Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Python与爬虫领域研究与…

力扣 343. 整数拆分 (JAVA 记忆化搜索->动态规划)

给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得的最大乘积 。 示例 1: 输入: n 2 输出: 1 解释: 2 1 1, 1 1 1。 示例 2: 输入: n 10 输出: 36 解释: 10 3 …

一次tomcat实战jvm线上问题定位排查和解决

问题分析&#xff1a; 问题来源是客户通过闲鱼找到了我这边进行问题的排查&#xff0c;给我发了一个报错日志&#xff0c;让我帮忙分析。 首先他的项目比较老&#xff0c;很多年以前开发的软件&#xff0c;但是具体做什么业务我不知道。下面来看日志的报错分析。 问题&#…

【Linux】软硬链接

文章目录 软链接硬链接软硬链接的使用场景&#xff1a;软链接的使用场景硬链接的应用场景 总结 软链接 软链接是一种指向文件或目录的快捷方式&#xff0c;是文件系统中非常重要的功能。它类似于Windows中的快捷方式&#xff0c;但更灵活&#xff0c;可以跨文件系统创建。 ln…

操作系统(5)进程

一、定义与特点 定义&#xff1a;进程是计算机中的程序关于某数据集合上的一次运行活动&#xff0c;是系统进行资源分配和调度的基本单位&#xff0c;是操作系统结构的基础。 特点&#xff1a; 动态性&#xff1a;进程是动态创建的&#xff0c;有它自身的生命周期&#xff0c;…

安宝特分享 | AR技术助力医院总院与分院间的远程面诊

随着科技的迅猛发展&#xff0c;增强现实&#xff08;AR&#xff09;技术在各行各业的应用愈发广泛&#xff0c;特别是在医疗领域&#xff0c;其潜力和价值正在被不断挖掘。在现代医疗环境中&#xff0c;患者常常面临“看病难、看病远、看病急”等诸多挑战&#xff0c;而安宝特…

CNCF云原生生态版图-分类指南(三)- 运行时

CNCF云原生生态版图-分类指南&#xff08;三&#xff09;- 运行时 CNCF云原生生态版图-分类指南三、运行时&#xff08;Runtime&#xff09;&#xff08;一&#xff09;云原生存储&#xff08;Cloud Native Storage&#xff09;1. 是什么&#xff1f;2. 解决什么问题&#xff1…

通俗易懂的 Nginx 反向代理 配置

通俗易懂的 Nginx 反向代理 配置 首先 root 与 alias 的区别 root 是直接拼接 root location location /i/ {root /data/w3; }当请求 /i/top.gif &#xff0c;/data/w3/i/top.gif 会被返回。 alias 是用 alias 替换 location location /i/ {alias /data/w3/images/; }当请…

HiveQL命令(一)- 数据库操作

文章目录 前言一、数据库操作1. 创建数据库1.1 语法及解释1.2 创建数据库示例 2. 查看数据库2.1 查看所有数据库2.2 查看数据库信息2.2.1 语法及解释2.2.2 查看数据库信息示例 3. 切换数据库3.1 语法3.2 示例 4. 修改数据库4.1 语法4.2 示例 5. 删除数据库5.1 语法及解释5.2 示…

Ubuntu22.04安装docker desktop遇到的bug

1. 确认已启用 KVM 虚拟化 如果加载了模块&#xff0c;输出应该如下图。说明 Intel CPU 的 KVM 模块已开启。 否则在VMware开启宿主机虚拟化功能&#xff1a; 2. 下一步操作&#xff1a; Ubuntu | Docker Docs 3. 启动Docker桌面后发现账户登陆不上去&#xff1a; Sign in | …

FPGA实现GTP光口数据回环传输,基于Aurora 8b/10b编解码架构,提供2套工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的所有工程源码总目录----方便你快速找到自己喜欢的项目我这里已有的 GT 高速接口解决方案 3、工程详细设计方案工程设计原理框图用户数据发送模块基于GTP高速接口的数据回环传输架构GTP IP 简介GTP 基本结构GTP 发送和接收…

(二)多智能体强化学习

目录 前言 一、多智能体强化学习的概念 二、多智能体面临的问题 三、现有算法简介 总结 前言 基于上一篇文章对于强化学习基础概念的介绍&#xff0c;本篇文章针对多智能体强化学习进行介绍和总结&#xff0c;帮助大家了解多智能体的基本概念以及算法&#xff0c;方便大家…

【Linux网络编程】传输协议UDP

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站 &#x1f308;个人主页&#xff1a; 南桥几晴秋 &#x1f308;C专栏&#xff1a; 南桥谈C &#x1f308;C语言专栏&#xff1a; C语言学习系…

汽车车牌识别数据集,支持YOLO,COCO,VOC格式的标注,8493张图片,可识别多种环境下的车牌

汽车车牌识别数据集&#xff0c;支持YOLO&#xff0c;COCO&#xff0c;VOC格式的标注&#xff0c;8493张图片&#xff0c;可识别多种环境下的车牌 数据集分割 训练组82&#xff05; 6994图片 有效集12&#xff05; 999图片 测试集6% 500图片 预处理 自动…