TCP socket

ops/2024/9/23 3:29:09/

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;
}


http://www.ppmy.cn/ops/114559.html

相关文章

python selenium网页操作

一、安装依赖 pip install -U seleniumselenium1.py&#xff1a; from selenium import webdriver from selenium.webdriver.common.by import Bydriver webdriver.Chrome() driver.get("https://www.selenium.dev/selenium/web/web-form.html") title driver.ti…

第七章 监听器

一、介绍 监听器的作用是被观察的对象发生某些情况时&#xff0c;自动触发代码的执行。监听器时GOF设计模式中&#xff0c;观察者模式的典型案例。观察者模式: 当被观察的对象发生某些改变时, 观察者自动采取对应的行动的一种设计模式。在JavaWeb中&#xff0c;可以使用监听器…

用终端请求接口

在终端&#xff08;命令行界面&#xff09;中请求接口&#xff0c;通常会使用curl命令&#xff0c;这是一个强大的命令行工具&#xff0c;用于传输数据。curl支持多种协议&#xff0c;包括HTTP、HTTPS、FTP等。下面是一些使用curl在终端中请求HTTP接口的基本示例。 1. 发送GET…

怎么让Nginx可以访问某一IP的每个后台controller接口

http { upstream backend { server 192.168.1.10; # 后端服务器IP } server { listen 80; location /controller1/ { ##proxy_pass http://localhost:801; proxy_pass http://backend/controller1/; # 后端controller1…

分布式事务学习笔记(四)微服务实现Stata AT模式、Stata Saga模式介绍

文章目录 前言4 Seata AT 模式4.1 实现原理4.2 脏写问题4.3 微服务实现AT模式4.3.1 新建数据库表4.3.2 修改配置文件4.3.3 重启服务并测试 5 Seata Saga 模式 前言 分布式事务学习笔记(一)分布式事务问题、CAP定理、BASE理论、Seata 分布式事务学习笔记(二)Seata架构、TC服务器…

Java 微服务框架 HP-SOA v1.1.4

HP-SOA 功能完备&#xff0c;简单易用&#xff0c;高度可扩展的Java微服务框架。 项目主页 : https://www.oschina.net/p/hp-soa下载地址 : https://github.com/ldcsaa/hp-soa开发文档 : https://gitee.com/ldcsaa/hp-soa/blob/master/README.mdQQ Group: 44636872, 66390394…

好用的工具网址

代码类&#xff1a; 1,json解析&#xff1a;JSON在线解析及格式化验证 - JSON.cn 2.传参转化编码 在线url网址编码、解码器-BeJSON.com 日常&#xff1a; 1.莆田医院查询&#xff1a;滚蛋吧&#xff01;莆田系

最新免费域名申请

在互联网时代&#xff0c;每个码农都想拥有一个免费的域名&#xff0c;方便开发调试&#xff0c;也可用作自己网站等。如何申请一个免费的域名&#xff0c;时间上先错过了freenom&#xff0c;后面又错过nic.eu.org申请(现在申请时间长且很难通过)&#xff0c;直到最近又有免费的…