Linux下套接字TCP实现网络通信

Linux下套接字TCP实现网络通信

文章目录

  • Linux下套接字TCP实现网络通信
  • 1.引言
  • 2.具体实现
    • 2.1接口介绍
      • 1.socket()
      • 2.bind()
      • 3.listen()
      • 4.accept()
      • 5.connect()
    • 2.2 服务器端server.hpp
    • 2.3服务端server.cc
    • 2.4客户端client.cc

1.引言

套接字(Socket)是计算机网络中实现网络通信的一种编程接口。它提供了应用程序与网络通信之间的一座桥梁,因为它允许应用程序通过网络发送和接收相应的数据以实现不同主机之间的通信。
在这里插入图片描述

通常套接字由以下两部分组成:

1.网络IP和端口号:IP用来标识主机,而端口号可以标识到单台主机的唯一进程。

2.通信协议:套接字通过规定通信协议来制定数据传输和发送的规则。常见的有TCP和UDP等协议。

TCP是一种面向连接的协议,提供可靠的、有序的、基于字节流的数据传输。

UDP是一种无连接的协议,提供不可靠的、无序的、基于数据报的数据传输。

​ 今天我们来学习TCP实现网络通信。TCP由于能提供可靠、基于字节流的数据传输,使用率与使用场景也比UDP多很多。

我们来看看能实现出什么样的结果(聊天室模拟两个用户随机通信):

若不开启服务端就只开启客户端的话,那么就会像打游戏的某些情况连不上:
在这里插入图片描述

当服务端和客户端都开启后就可以正常通信了:

在这里插入图片描述

这里我们还是通过客户端给服务器端发送消息,通过TCP链接实现通信。

那么事不宜迟,我们马上开始分享实现过程吧!

2.具体实现

2.1接口介绍

1.socket()

​ socket函数是用于创建套接字的函数,创建成功返回文件描述符fd,失败返回-1

int socket(int domain, int type, int protocol);

​ 参数说明:

  • domain

    :指定套接字的地址族(Address Family)

    今天我们选择:

    • AF_INET:IPv4 地址族
  • type

    :指定套接字的类型(Socket Type)

    今天我们选择:

    • SOCK_STREAM:有连接的字节流套接字,用于TCP协议
  • protocol

    :可选参数,指定具体的传输协议。常用的有:

    ​ 今天我们选择:

    • 0:自动选择合适的协议

2.bind()

​ 在Linux下,bind() 函数用于将一个套接字(socket)与特定的IP地址和端口号进行绑定

*int bind(int sockfd, const struct sockaddr addr,socklen_t addrlen);

参数说明:

  • sockfd:要进行绑定的套接字的文件描述符。
  • addr:指向一个 struct sockaddr 结构体的指针,其中包含要绑定的IP地址和端口号信息。
  • addrlenaddr 结构体的长度。

在绑定bind的第二个参数中,我们也需要用到库中定义好的sockaddr_in结构体来初始化!

具体结构体struct sockaddr_in说明:

结构体中有三个值也需要初始化指定一下:

  1. sin_family:表示地址族(Address Family),一般为 AF_INET

  2. sin_port:表示端口号。它是一个 16 位的整数,使用网络字节序(大端字节序)表示。在使用时,通常需要使用 htons() 函数将主机字节序转换为网络字节序。

  3. sin_addr:表示 IPv4 地址。它是一个 struct in_addr 类型的结构体,用于存储 32 位的 IPv4 地址。

    一般服务端用INADDR_ANY,让udp_server在启动时候可以绑定任何ip.

    ​ 客户端用inet_addr函数将字符串转化成32位无符号整数


3.listen()

listen()函数:将套接字设置为监听状态,等待连接请求。

参数:

  • sockfd:套接字的文件描述符。这里我们选择前面socket创建好的返回值.
  • backlog:指定等待连接队列的最大长度。一般不会太大,我们这里写32即可。

4.accept()

accept() 函数:接受客户端的连接请求,创建一个新的套接字用于与客户端进行通信。

参数:

  • sockfd:套接字的文件描述符。这里我们选择前面socket创建好的返回值.
  • addr:指向客户端地址的结构体指针。创建一个sockaddr的结构体强转一下(struct sockaddr*)即可。
  • addrlen:客户端地址结构体的字节大小。创建一个socklen_t类型的值用来计算结构体大小。

5.connect()

connect() 函数:发起与远程主机建立TCP连接的请求。

参数:

  • sockfd:套接字的文件描述符。这里我们选择前面socket创建好的返回值.
  • addr:指向远程主机地址的结构体指针。创建一个sockaddr的结构体强转一下(struct sockaddr*)即可。
  • addrlen:远程主机地址结构体的字节大小。创建一个socklen_t类型的值用来计算结构体大小。

2.2 服务器端server.hpp

在整个服务器端server.hpp中,我们需要创建tcpServer类,并在类中建立这些成员:监听套接字、端口号等.

在类中我们还需要初始化服务器InitServer()和启动服务器Start()两个接口。

服务器端具体实现思路是:我们创建套接字socket()后开始绑定bind(),之后监听listen(),监听成功后我们获取链接accept()即可。

思路简单,但是实现还需要很多事完成:

static const uint16_t defaultport = 8081;
static const int backlog = 32;
using func_t = std::function<std::string(const std::string&)>;class tcpServer
{public:tcpServer(func_t func,uint16_t port = defaultport):_func(func),_port(port),_quit(true){}~tcpServer() {}void InitServer(){//1.创建套接字_listensock = socket(AF_INET,SOCK_STREAM,0);if(_listensock < 0){std::cerr << "create socket error" << std::endl;exit(-1);}//2.绑定struct sockaddr_in local;memset(&local,0,sizeof(local)); //清空结构体local.sin_family = AF_INET;local.sin_port = htons(_port);    //主机转网络local.sin_addr.s_addr = htonl(INADDR_ANY);if(bind(_listensock,(struct sockaddr*)&local,sizeof(local)) < 0){std::cerr << "bind error" << std::endl;exit(-2);}//3.监听(tcp)if(listen(_listensock,backlog) < 0){std::cerr <<" listen error" << std::endl;exit(-3);}}void Start(){_quit = false; //运行时设置位运行状态,即不退出的状态while(!_quit) //服务器死循环{struct sockaddr_in client;socklen_t len = sizeof(client);//4.获取链接acceptint sock = accept(_listensock,(struct sockaddr*)&client,&len);if(sock < 0) {std::cerr <<"accept error " <<std::endl;continue;} //揽客的sock失败后继续即可//5.获取链接成功std::cout<< "获取链接成功" << sock << " from " << _listensock <<  std::endl;service(sock);}}void service(int sock) //服务{char buffer[1024];while(true){ssize_t s = read(sock,buffer,sizeof(buffer)-1);if(s > 0) //代表成功读取{buffer[s] = 0;std::string res = _func(buffer); //回调显示std::cout<< res <<std::endl;write(sock,res.c_str(),res.size());}else if(s == 0) //代表读到文件结尾 在网络中就相当于对方关闭链接{close(sock);std::cout << "quit" <<std::endl;break;}else //文件读取失败{close(sock);std::cerr << " read error" <<std::endl;break;}}}private:uint16_t _port; //端口号int _listensock; //监听套接字bool _quit; //代表服务器没有运行的状态func_t _func; //回调包装器,为了后面输出后回显
};

2.3服务端server.cc

在服务端的主文件中,我们直接包含上面的头文件。

我们期望的用法是:./tcp_server port,代表运行可执行文件后面需要带一个参数:端口号

所以我们能够从用户中输入的port,通过main函数中的**char* argv[]**参数列表中获取到。并传给tcpSercer类中初始化与启动服务器即可。

#include "server.hpp"
#include<memory>
using namespace std;static void usage(string proc) //使用手册,代表运行可执行文件后面需要带一个参数:端口号
{std::cout << "Usage:\n\t" << proc << "port\n" <<std::endl;}std::string echo(const std::string& message)//输出回显
{return message;
}//期望用法:./tcp_server port
int main(int argc,char* argv[])
{if(argc != 2) //输入的不是两个参数,说明你不会用。输出使用手册{usage(argv[0]);exit(-1);}uint16_t port = atoi(argv[1]); //强转成能够使用的类型unique_ptr<tcpServer> ts(new tcpServer(echo,port));//采用智能指针创建释放资源ts->InitServer();ts->Start();return 0;
}

2.4客户端client.cc

在客户端中我们conncet尝试链接到服务器端,这里需要做一个重连反馈:正在尝试重连…

我们期望运行格式:./client serverip serverport,代表运行可执行文件后需要两个参数:IP和端口

我们从用户输入的两个参数中传给main,并通过main参数char* argv[]参数列表获取到,之后获取到直接转化即可。


static void usage(string proc)
{std::cout << "Usage:\n\t" << proc << "serverip serverport\n" <<std::endl;}
//期望使用:./client serverip serverport 
int main(int argc,char* argv[])
{if(argc != 3){usage(argv[0]);exit(-2);}string serverip = argv[1]; //获取到参数uint16_t port = atoi(argv[2]);//1.创捷套接字int sock = socket(AF_INET,SOCK_STREAM,0);if(sock < 0){std::cerr << " socket error" <<std::endl;exit(-1);}//2.客户端需要链接服务器 --connectstruct sockaddr_in server; //memset(&server,0,sizeof(server)); //清空结构体server.sin_family = AF_INET;//初始化结构体server.sin_port = htons(port);//server.sin_addr.s_addr = inet_addr(serverip.c_str()); //客户端inet_aton(serverip.c_str(),&(server.sin_addr));int cnt = 5;while(connect(sock,(struct sockaddr*)&server,sizeof(server)) != 0) //如果绑定失败{sleep(1);std::cout<<"正在尝试重连... 重连次数:" <<cnt-- <<std::endl;if(cnt <= 0) break;}    if(cnt <= 0){cerr<< "服务器连接失败"<<endl;exit(-1);}//3.连接成功while(true) //连接成功后从客户端直接输入发送数据{string line;char buffer[1024];cout<<"Enter>> "; getline(cin,line);write(sock,line.c_str(),line.size()); //给缓冲区写数据ssize_t s = read(sock,buffer,sizeof(buffer) -1);if(s > 0)//正常写{buffer[s] = 0;cout<< " server rcho >>>" <<buffer <<endl;}else if(s == 0) //写结束{cerr << "server quit" <<endl;break;}else{ //异常cerr<< " read error " <<endl;break;}}close(sock);//关闭套接字,管不管都可以return 0;
}

最后运行之后就能获得我们之前通信的结果了:

在这里插入图片描述

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

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

相关文章

1688API技术解析,实现获得1688商品详情

要实现获得1688商品详情&#xff0c;你需要使用1688 API。1688 API是阿里巴巴旗下的开放平台&#xff0c;它提供了一套丰富的接口&#xff0c;可以让开发者通过编程的方式获取到1688网站上的商品信息。 首先&#xff0c;你需要在阿里开放平台注册一个账号&#xff0c;并创建一…

【NLP的python库(01/4) 】: NLTK

一、说明 NLTK是一个复杂的库。自 2009 年以来不断发展&#xff0c;它支持所有经典的 NLP 任务&#xff0c;从标记化、词干提取、词性标记&#xff0c;包括语义索引和依赖关系解析。它还具有一组丰富的附加功能&#xff0c;例如内置语料库&#xff0c;NLP任务的不同模型以及与S…

深眸科技创新赋能视觉应用产品,以AI+机器视觉解决行业应用难题

随着工业4.0时代的加速到来&#xff0c;我国工业领域对于机器视觉技术引导的工业自动化和智能化需求持续上涨&#xff0c;国内机器视觉行业进入快速发展黄金期&#xff0c;但需求广泛出现同时也对机器视觉产品的检测能力提出了更高的要求。 传统机器视觉由人工分析图像特征&am…

JAVA JNA 调用C接口的三种方式

文章目录 1. 准备一个共享库文件2. JNA姿势1—继承Library接口3. JNA姿势2—直接NativeLibrary.getInstance3. JNA姿势3—Native方法 1. 准备一个共享库文件 test.c #include <stdio.h> int test(char *input){printf("input:%s\n",input);return 0; }libtes…

从Matrix-ResourceCanary看内存泄漏监控

作者&#xff1a;小海编码日记 不同于LeakCanary&#xff0c;在Matrix中&#xff0c;主要是通过Resource Canary来监控内存泄漏问题的&#xff0c;且监听的泄漏对象只支持Activity&#xff0c;官方说明如下&#xff1a; 结合分析LeakCanary的经验可知&#xff0c;要实现Activit…

fastadmin iis伪静态应用入口文件index.php

<?xml version"1.0" encoding"UTF-8"?> <configuration><system.webServer><rewrite><rules><rule name"OrgPage" stopProcessing"true"><match url"^(.*)$" /><conditions…

【python知识】用 Tkinter实现“剪刀-石头-布”和“弹球游戏 ”

一、提要 Tkinter是一个Python内置模块&#xff0c;它提供了一个简单易用的界面来创建GUI。 在实现一些动态的画面、如游戏还是需要一些创新性思维的。在本文中&#xff0c;我们将使用 Tkinter 探索 Python GUI 编程。我们将介绍 Tkinter 的基础知识&#xff0c;并演示如何使用…

Element Plus 日期选择器的使用和属性

element plus 日期选择器如果如果没有进行处理 他会返回原有的属性值data格式 如果想要获取选中的日期时间就需要通过以下的代码来实现选中的值 format"YYYY/MM/DD" value-format"YYYY-MM-DD" <el-date-pickerv-model"formInline.date" type&…

「MySQL-05」MySQL Workbench的下载和使用

目录 一、MySQL workbench的下载和安装 1. MySQL workbench介绍 2. 到MySQL官网下载mysql workbench 3. 安装workbench 二、创建能远程登录的用户并授权 1. 创建用户oj_client 2. 创建oj数据库 3. 给用户授权 4. 在Linux上登录用户oj_client检查其是否能操作oj数据库 三、使用…

gerrit 如何提交进行review

前言 本文主要介绍如何使用gerrit进行review。 下述所有流程都是参考&#xff1a; https://gerrit-review.googlesource.com/Documentation/intro-gerrit-walkthrough.html 先给一个commit后但是还没有push上去的一个办法&#xff1a; git reset --hard HEAD^可以多次reset.…

DC/DC开关电源学习笔记(一)开关电源技术概述

&#xff08;一&#xff09;开关电源技术概述 1.什么是开关电源&#xff1f;2.开关电源技术概述2.1 小型化、薄型化、轻量化、高频化2.2 高可靠性2.3 低噪声2.4 采用计算机辅助设计和控制 1.什么是开关电源&#xff1f; 开关模式电源&#xff08;Switch Mode Power Supply&…

opencv的使用(Ubuntu linux环境,AS jni,AS java)

最近要完成一个功能&#xff0c;就是把四个视频合成左右上下分布的一个视频。尝试很多方法&#xff0c;最终使用opencv来实现该功能。&#xff08;通过opencv实现的视频好像没有声音。&#xff09;研究的步骤&#xff0c;首先在Ubuntu环境测试&#xff0c;该功能是否实现。然后…

【Luniux】解决Ubuntu外接显示器不显示的问题

Luniux】解决Ubuntu外接显示器不显示的问题 文章目录 Luniux】解决Ubuntu外接显示器不显示的问题1. 检查nvidia显卡驱动是否正常2. 更新驱动3. 检查显示器是否能检测到Reference 1. 检查nvidia显卡驱动是否正常 使用命令行 nvidia-smi来检查显卡驱动是否正常&#xff0c;如果…

3、监测数据采集物联网应用开发步骤(3)

监测数据采集物联网应用开发步骤(2) 系统整体结构搭建 新建项目 输入项目名称&#xff1a;MonitorData 所谓兵马未动粮草先行&#xff0c;按下图创建好对应的模块备用&#xff1a; com.plugins 业务插件模块 com.zxy.adminlog 日志或文本文…

《C和指针》笔记12: 存储类型(自动变量、静态变量和寄存器变量)

文章目录 1. 自动变量&#xff08;auto&#xff09;1.1 自动变量的初始化 2. 静态变量&#xff08;static&#xff09;2.1 静态变量的初始化 3. 寄存器变量&#xff08;register&#xff09; 1. 自动变量&#xff08;auto&#xff09; 在代码块内部声明的变量的缺省存储类型是…

小白必看:期权行权前必须了解的问题。

期权的本质是一个买权或是卖权&#xff0c;也就是说你是权利方的话&#xff0c;你拥有以约定价格向对手方买入&#xff08;买权&#xff09;或卖出&#xff08;卖权&#xff09;一定数量标的的权利。期权行权就是从对手方买入&#xff0c;或向其卖出标的&#xff01;下文介绍小…

葡萄叶病害识别(图像连续识别和视频识别,Python代码,pyTorch框架)

葡萄叶病害识别&#xff08;图像连续识别和视频识别&#xff0c;Python代码&#xff0c;pyTorch框架&#xff09;_哔哩哔哩_bilibili 葡萄数据集 第一个文件夹为 Grape Black Measles&#xff08;葡萄黑麻疹&#xff09;病害&#xff08;3783张&#xff09; Grape Black rot葡…

C#调用barTender打印标签示例

使用的电脑需要先安装BarTender 我封装成一个类 using System; using System.Windows.Forms;namespace FT_Tools {public class SysContext{public static BarTender.Application btapp new BarTender.Application();public static BarTender.Format btFormat;public void Q…

【pytorch】Unfold和Fold的互逆操作

1. 参数定义 Unfold https://pytorch.org/docs/stable/generated/torch.nn.Unfold.html#torch.nn.Unfold Fold https://pytorch.org/docs/stable/generated/torch.nn.Fold.html#torch.nn.Fold 注意&#xff1a;参数当中的padding是在四周边补零&#xff0c;而当fold后的尺寸…

Property ‘sqlSessionFactory‘ or ‘sqlSessionTemplate‘ are required

项目场景&#xff1a; 最近因为公司业务需要在搭一个新架构&#xff0c;用的springboot3和jdk17,在整合mybatis多数据源的时候报错 &#xff08;引用的mybatisplus 和 mybatisplusjion的是最新的包-2023-08-26&#xff09; Error creating bean with name ‘XXXServiceImpl’:…