当前位置: 首页 > news >正文

TCP socket

TCP的socket和UDP大同小异,基本的代码结构都是相同的。一些相同的接口本文就不赘述了,例如,socket,bind,有需要看这篇文章UDP socket

服务端server

两步:初始化服务端,运行服务端

初始化服务端

创建socket,bind IP和端口号,listen监听

socket的第二个参数使用SOCK_STREAM,因为与UDP不同的是TCP面向字节流。其余的与UDP无异。

listen接口

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 

    void init(){// socketsockfd_ = socket(AF_INET, SOCK_STREAM, 0);if (sockfd_ < 0){exit(1);}// bindstruct sockaddr_in local;local.sin_family = AF_INET;inet_pton(AF_INET, ip_.c_str(), &local.sin_addr);local.sin_port = htons(port_);int n = bind(sockfd_, (struct sockaddr *)&local, sizeof(local));if (n < 0){exit(2);}// listenif (listen(sockfd_, 10) < 0){exit(3);}}

运行服务端

四步:accept接收请求,接收数据,处理数据,最后发送数据

accept接口

 初始化socket得到的文件描述符是用来listen的,而accept获得的文件描述符才是用来传输数据的,read和write接口就是用这个描述符的。

read和write很简单,第一个参数是文件描述符,第二个参数是读取/发送的数据地址,第三个参数是数据的大小

void run(){while (1){// acceptstruct sockaddr_in client;socklen_t len = sizeof(client);int lis_fd = accept(sockfd_, (struct sockaddr *)&client, &len);// 接收数据char buf[1024] = {0};int n = read(lis_fd, buf, sizeof(buf));if (n < 0){break;}else if (n == 0){cout << "quit" << endl;break;}else{buf[n] = 0;std::cout << "server get msg:" << buf << std::endl;// 处理数据std::string msg = "server say: I have get msg >_";msg += buf;write(lis_fd, msg.c_str(), msg.size());}}}

客户端client

五步:创建socket(同服务端)->bind(由OS完成)->connect请求连接->发送数据write->接收数据read

connect接口

第一个参数是socket获得的文件描述符,第二个是要连接的服务端的属性结构体(记得类型转换),TCP的结构体数据类型是struct sockaddr_in。第三个是结构体大小

int main(int argc, char *argv[])
{if (argc != 3){std::cout << argv[0] << "[ip]" << "[port]" << std::endl;return -1;}// 获取命令行参数uint16_t port = stoi(argv[2]);string ip = argv[1];struct sockaddr_in server;server.sin_family = AF_INET;server.sin_port = htons(port);server.sin_addr.s_addr = inet_addr(ip.c_str());while (1){// socketint sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){std::cout << "client create fail" << endl;exit(1);}// bind由os随机分配端口完成// connectint n = connect(sockfd, (struct sockaddr *)&server, (socklen_t)sizeof(server));if (n < 0){std::cout << "client connect fail" << std::endl;exit(2);}std::string msg;std::cout << "Please Enter>_";getline(std::cin, msg);// 发送数据n = write(sockfd, msg.c_str(), msg.size());if (n < 0){std::cout << "write fail" << std::endl;continue;}char buf[1024] = {0};// 接收数据n = read(sockfd, buf, sizeof(buf));if (n < 0){std::cout << "read fail" << std::endl;continue;}buf[n] = 0;cout << buf << endl;}
}

序列化和反序列化

序列化是将数据结构或对象转换为一种可以存储或传输的格式,反序列化是序列化的逆过程,它将序列化后的数据重新还原为原始的对象或数据结构。

其实这本质和协议是一样的,都是一种约定。服务端和客户端都按照一个相同的规则将收发的数据做处理,以便于数据的传输。

序列化和反序列化的应用场景

  1. 网络编程

    客户端与服务器之间传输数据时,往往通过序列化和反序列化的方式来进行。例如,在你写的 TCP 客户端/服务器代码中,客户端需要将数据(如数学表达式)序列化后发送给服务器,服务器再反序列化处理并返回结果。
  2. 数据持久化

    将内存中的数据或对象序列化后保存到数据库或文件中,以便稍后可以重新加载数据并继续使用。
  3. 跨进程通信

    当两个不同的进程需要交换数据时,序列化可以将复杂数据结构转换为字节流,方便在进程之间传递。

源码

//tcpserver.hpp
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>enum
{SocketFail = 1,BindFail,ListenError
};
class tcpServer
{
public:tcpServer(std::string ip = "0.0.0.0", uint16_t port = 8888): ip_(ip), port_(port){}~tcpServer(){}void init(){// socketsockfd_ = socket(AF_INET, SOCK_STREAM, 0);if (sockfd_ < 0){exit(SocketFail);}// bindstruct sockaddr_in local;local.sin_family = AF_INET;inet_pton(AF_INET, ip_.c_str(), &local.sin_addr);local.sin_port = htons(port_);int n = bind(sockfd_, (struct sockaddr *)&local, sizeof(local));if (n < 0){exit(BindFail);}// listenif (listen(sockfd_, 10) < 0){exit(ListenError);}}void run(){while (1){// acceptstruct sockaddr_in client;socklen_t len = sizeof(client);int lis_fd = accept(sockfd_, (struct sockaddr *)&client, &len);// 接收数据char buf[1024] = {0};int n = read(lis_fd, buf, sizeof(buf));if (n < 0){break;}else if (n == 0){cout << "quit" << endl;break;}else{buf[n] = 0;std::cout << "server get msg:" << buf << std::endl;// 处理数据std::string msg = "server say: I have get msg >_";msg += buf;write(lis_fd, msg.c_str(), msg.size());}}}private:int sockfd_;std::string ip_;uint16_t port_;
};
//tcpclient.cpp
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>int main(int argc, char *argv[])
{if (argc != 3){std::cout << argv[0] << "[ip]" << "[port]" << std::endl;return -1;}// 获取命令行参数uint16_t port = stoi(argv[2]);string ip = argv[1];struct sockaddr_in server;server.sin_family = AF_INET;server.sin_port = htons(port);server.sin_addr.s_addr = inet_addr(ip.c_str());while (1){// socketint sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){std::cout << "client create fail" << endl;exit(1);}// bind由os随机分配端口完成// connectint n = connect(sockfd, (struct sockaddr *)&server, (socklen_t)sizeof(server));if (n < 0){std::cout << "client connect fail" << std::endl;exit(2);}std::string msg;std::cout << "Please Enter>_" << std::endl;getline(std::cin, msg);// 发送数据n = write(sockfd, msg.c_str(), msg.size());if (n < 0){std::cout << "write fail" << std::endl;continue;}char buf[1024] = {0};// 接收数据n = read(sockfd, buf, sizeof(buf));if (n < 0){std::cout << "read fail" << std::endl;continue;}buf[n] = 0;cout << buf << endl;}
}
//main.cpp
#include "tcpServer.hpp"
#include <memory>int main()
{std::unique_ptr<tcpServer> server(new tcpServer);server->init();server->run();return 0;
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • G1: Yunli‘s Subarray Queries (easy version)(1900)(定长区间众数)
  • SpringCloud的学习,Consul服务注册与发现、分布式配置,以及 服务调用和负载均衡
  • 【自动化测试】UI自动化的分类、如何选择合适的自动化测试工具以及其中appium的设计理念、引擎和引擎如何工作
  • Ubuntu 22.04 LTS 上安装 Docker
  • 使用jmeter做性能测试实践过程中需要注意什么
  • FreeRTOS学习笔记(七)信号量
  • 《C++代码高度优化之双刃剑:避免过度优化引发的“暗雷”》
  • MySQL中的redo log、 undo log、bin log
  • flink中startNewChain() 的详解
  • 【计网】从零开始使用UDP进行socket编程 --- 服务端业务实现
  • 相亲交友中的用户画像构建方法探讨
  • cfs三层靶机——内网渗透
  • centos中yum方式部署Jenkins
  • git github仓库管理
  • idea激活页面怎么打开
  • 【402天】跃迁之路——程序员高效学习方法论探索系列(实验阶段159-2018.03.14)...
  • Apache Spark Streaming 使用实例
  • Laravel深入学习6 - 应用体系结构:解耦事件处理器
  • webpack入门学习手记(二)
  • 聊聊hikari连接池的leakDetectionThreshold
  • 码农张的Bug人生 - 见面之礼
  • 如何正确配置 Ubuntu 14.04 服务器?
  • 通过获取异步加载JS文件进度实现一个canvas环形loading图
  • 微信小程序:实现悬浮返回和分享按钮
  • 移动端 h5开发相关内容总结(三)
  • 原创:新手布局福音!微信小程序使用flex的一些基础样式属性(一)
  • 运行时添加log4j2的appender
  • ​油烟净化器电源安全,保障健康餐饮生活
  • ###51单片机学习(1)-----单片机烧录软件的使用,以及如何建立一个工程项目
  • (2021|NIPS,扩散,无条件分数估计,条件分数估计)无分类器引导扩散
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第2节(共同的基类)
  • (Oracle)SQL优化基础(三):看懂执行计划顺序
  • (阿里巴巴 dubbo,有数据库,可执行 )dubbo zookeeper spring demo
  • (纯JS)图片裁剪
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (附源码)springboot宠物医疗服务网站 毕业设计688413
  • (附源码)springboot家庭财务分析系统 毕业设计641323
  • (免费领源码)Java#Springboot#mysql农产品销售管理系统47627-计算机毕业设计项目选题推荐
  • (篇九)MySQL常用内置函数
  • (太强大了) - Linux 性能监控、测试、优化工具
  • (一)WLAN定义和基本架构转
  • (转) RFS+AutoItLibrary测试web对话框
  • (转)Android学习笔记 --- android任务栈和启动模式
  • (转)eclipse内存溢出设置 -Xms212m -Xmx804m -XX:PermSize=250M -XX:MaxPermSize=356m
  • (转)Oracle存储过程编写经验和优化措施
  • (转)菜鸟学数据库(三)——存储过程
  • (转)大道至简,职场上做人做事做管理
  • (轉貼)《OOD启思录》:61条面向对象设计的经验原则 (OO)
  • ./mysql.server: 没有那个文件或目录_Linux下安装MySQL出现“ls: /var/lib/mysql/*.pid: 没有那个文件或目录”...
  • .NET DataGridView数据绑定说明
  • .net 获取某一天 在当月是 第几周 函数
  • .NET(C#、VB)APP开发——Smobiler平台控件介绍:Bluetooth组件
  • .NET/C# 判断某个类是否是泛型类型或泛型接口的子类型
  • .net的socket示例
  • .NET开源纪元:穿越封闭的迷雾,拥抱开放的星辰