【网络编程】TCP Socket编程

news2024/11/25 14:43:24

TCP Socket编程

  • 1. ServerSocket
  • 2. Socket
  • 3. TCP的长短连接
  • 4. Socket 通信模型
  • 5. 代码示例:TCP 回显服务器

流套接字: 使用传输层TCP协议
TCP: 即Transmission Control Protocol(传输控制协议),传输层协议。
TCP的特点:

  1. 有连接
  2. 可靠传输
  3. 面向字节流
  4. 有接收缓冲区,也有发送缓冲区
  5. 大小不限

1. ServerSocket

ServerSocket 是创建TCP服务端Socket的API。

注意: ServerSocket 只能用于 服务器端。

构造方法:

方法签名方法说明
ServerSocket(int port)创建一个服务端流套接字Socket,并绑定到指定端口

方法:

方法签名方法说明
Socket accept()开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket对象,并基于该Socket建立与客户端的连接,否则阻塞等待
void close()关闭此套接字

2. Socket

Socket 是客户端Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回的服务端Socket。

构造方法:

方法签名方法说明
Socket(String host, int port)创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接

注意:这里面的 host 和 port 是要连接的服务器的 IP 地址和端口号。

方法:

方法签名方法说明
InetAddress getInetAddress()返回套接字所连接的地址
InputStream getInputStream()返回此套接字的输入流
OutputStream getOutputStream()返回此套接字的输出流

3. TCP的长短连接

TCP发送数据时,需要先建立连接,什么时候关闭连接就决定是短连接还是长连接:

短连接: 每次接收到数据并返回响应后,都关闭连接,即是短连接。也就是说,短连接只能一次收数据。
长连接: 不关闭连接,一直保持连接状态,双方不停的收发数据,即是长连接。也就是说,长连接可以多次收发数据。

两者区别如下:

  1. 建立连接、关闭连接的耗时:短连接每次请求、响应都需要建立连接,关闭连接;而长连接只需要第一次建立连接,之后的请求、响应都可以直接传输。相对来说建立连接,关闭连接也是要耗时的,长连接效率更高。
  2. 主动发送请求不同:短连接一般是客户端主动向服务端发送请求;而长连接可以是客户端主动发送请求,也可以是服务端主动发。
  3. 两者的使用场景有不同:短连接适用于客户端请求频率不高的场景,如浏览网页等。长连接适用于客户端与服务端通信频繁的场景,如聊天室,实时游戏等。

4. Socket 通信模型

在这里插入图片描述

5. 代码示例:TCP 回显服务器

服务器代码:

class TcpEchoServer {
    public ServerSocket serverSocket;//专门用来接受请求并建立链接
    public Socket clientSocket;//专门用来处理请求
    public TcpEchoServer(int port) throws IOException {
        this.serverSocket=new ServerSocket(port);
    }

    public void start() throws IOException {
        System.out.println("服务器启动!");
        //也可以利用线程池
        ExecutorService threadsPool= Executors.newCachedThreadPool();
        while(true){
            //接受请求
            clientSocket=serverSocket.accept();
//            //利用多线程才能让服务器同时处理多个客户端的请求
//            Thread t=new Thread(()->{
//                //建立链接并处理请求
//                try {
//                    createConnection(clientSocket);
//                } catch (IOException e) {
//                    throw new RuntimeException(e);
//                }
//            });
//            t.start();
            //创建线程池相对于每次创建一个线程来说效率更高一些
            threadsPool.submit(()->{
                try {
                    createConnection(clientSocket);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }
    }

    public void createConnection(Socket clientSocket) throws IOException {
        System.out.printf("[%s:%d]建立链接成功\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
        //三个步骤
        //1.读取客户端请求(根据打开的文件流确定了读取的是客户端发来的请求)
        //这里针对TCP的读写和对于文件的读写是一摸一样的
        //利用socket构造文件流
        try(InputStream inputStream=clientSocket.getInputStream()){//注意打开的流
            //直接利用scanner读取(利用原生的InputStream也是可以的,但Scanner更方便)
            Scanner scanner=new Scanner(inputStream);
            try(OutputStream outputStream=clientSocket.getOutputStream()){//注意打开的流
                while(true){
                    
                    if(!scanner.hasNext()){
                        System.out.printf("[%s:%d]断开链接\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
                        break;
                    }
                    //读取请求(TCP以字符流进行传输)
                    // 读到空白符/ 空格/换行才会停止
                    String request=scanner.next();
                    //2.根据请求计算响应
                    String response=process(request);
                    //3.返回响应(根据打开的文件流决定了是往客户端返回请求)
                    //为了方便用PrintWriter对OutputStream进行包裹
                    PrintWriter printWriter=new PrintWriter(outputStream);
                    // 因为使用 next,读到空白符/ 空格/换行才会停止,所以须使用 println 
                    printWriter.println(response);
                    printWriter.flush();
                    System.out.printf("[%d][req:%s resp:%s]\n",clientSocket.getPort(),request,response);
                }
            }
        }finally {
            clientSocket.close();//记得及时关闭
        }
    }

    public String process(String request){
        return request;
    }

    public static void main(String[] args) throws IOException {
        TcpEchoServer tcpEchoServer=new TcpEchoServer(9090);
        tcpEchoServer.start();
    }
}

客户端代码:

class TcpEchoClient {
    public Socket client;
    //TCP中客户端构造函数的ip和port指的是要链接的服务器的IP和port
    public TcpEchoClient(String serverIp, int serverPort) throws IOException {
        this.client = new Socket(serverIp, serverPort);
    }

    public void start() throws IOException {
        System.out.println("和服务器建立链接成功");
        Scanner scanner = new Scanner(System.in);
        //这里针对TCP的读写和对于文件的读写是一摸一样的
        //利用socket构造文件流
        try (InputStream inputStream = client.getInputStream()) {
            try (OutputStream outputStream = client.getOutputStream()) {
                //接收从控制台输入的字符串
                while (true) {
                    System.out.println("->");
                    String request = scanner.next();
                    //构造请求并发送请求(PrintWriter和Scanner对应)//注意文件流
                    PrintWriter printWriter = new PrintWriter(outputStream);
                    // 因为使用 next,读到空白符/ 空格/换行才会停止,所以须使用 println 
                    printWriter.println(request);
                    printWriter.flush();//如果不及时刷新,服务器可能不能及时接收到数据
                    //接收响应
                    Scanner respScanner = new Scanner(inputStream);
                    String response = respScanner.next();
                    //显示到控制台上
                    System.out.printf("[req:%s  resp:%s]\n", request, response);
                }
            }
        }
    }

    public static void main(String[] args) throws IOException {
        TcpEchoClient tcpEchoClient = new TcpEchoClient("127.0.0.1", 9090);
        tcpEchoClient.start();
    }
}

注意:当然要先启动服务器再启动客户端!

好啦! 以上就是对 TCP Socket编程的讲解,希望能帮到你 !
评论区欢迎指正 !

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Pycharm配置环境以及Teminal不能使用问题解决

Pycharm配置环境 配置好环境后点击Terminal Teminal不能使用问题解决 我的报错信息: Import-Module : 无法加载文件 D:\Anaconda\shell\condabin\Conda.psm1,因为在此系统上禁止运行脚本。 解决方案: 第一步.:在 Windows 下用…

K8S名称空间和资源配额

Kubernetes 支持多个虚拟集群,底层依赖于同一个物理集群。 这些虚拟集群被称为名称空间。名称空间namespace是k8s集群级别的资源,可以给不同的用户、租户、环境或项目创建对应的名称空间,例如,可以为test、dev、prod环境分别创建各…

服务器搭建(TCP套接字)-基础版(服务端)

一、socket 1.1、vim man查看socket :!man socket1.2、 依赖的头文件 #include <sys/types.h> #include <sys/socket.h>1.3、原型 int socket(int domain, int type, int protocol);domain说明AF_INETIPV4协议AF_INET6IPV6协议AF_LOCALUnix域协议 type说明S…

JavaScript中的垃圾回收机制

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ JavaScript的垃圾回收机制⭐ 内存管理⭐ 引用计数⭐ 标记-清除算法⭐ 内存泄漏⭐ 性能优化⭐ 使用delete操作符⭐ 注意循环中的变量引用⭐ 使用工具进行内存分析⭐ 使用合适的数据结构⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探…

企业架构LNMP学习笔记54

企业架构NoSQL数据库之MongoDB。 学习目标和内容&#xff1a; 1&#xff09;能够简单描述mongoDB的使用特点&#xff1a; 2&#xff09;能够安装配置启动MongoDB&#xff1b; 3&#xff09;能够使用命令行客户端简单操作MongoDB&#xff1b; 4&#xff09;能够实现基本的数…

vsftp3.0 匿名用户,本地用户,虚拟用户

整体配置介绍&#xff1a; 进入vsftpd配置文件 vim /etc/vsftpd/vsftpd.conf //输入i开始编辑&#xff0c;修改后按esc退出编辑&#xff0c;输入:wq后回车保存并退出anonymous_enableYES #接受匿名用户&#xff0c;默认无密码请求 lo…

01_Elasticsearch入门介绍

01_Elasticsearch入门介绍 Elasticsearch 是什么1、什么是搜索&#xff1f;2、如果用数据库做搜索会怎么样&#xff1f;3、什么是全文检索和Lucene&#xff1f;4、什么是Elasticsearch&#xff1f;5、Elasticsearch的功能6、Elasticsearch的适用场景7、Elasticsearch的特点 什么…

Anaconda成功安装之后没有在菜单列和桌面显示图标

1、进入命令提示符 2、输入cmd 3、进入到Anaconda安装路径 比如我装在F盘 4、然后输入 python .\Lib\_nsis.py mkmenus 回车 这时候菜单列就可以看到了

第 4 章 串(串的堆分配存储实现)

1. 背景说明 实现基本与定长分配一致&#xff0c;不过将定长分配改为动态分配&#xff0c;解除了长度限制&#xff0c;实现更加灵活。 2. 示例代码 1) status.h /* DataStructure 预定义常量和类型头文件 */#ifndef STATUS_H #define STATUS_H#define CHECK_NULL(pointer) if …

[JAVAee]spring-Bean对象的执行流程与生命周期

执行流程 spring中Bean对象的执行流程大致分为四步: 启动Spring容器实例化Bean对象Bean对象注册到Spring容器中将Bean对象装配到所需的类中 ①启动Spring容器,在main方法中获取spring上下文对象并配备spring. import demo.*;import org.springframework.context.Applicati…

nacos动态配置刷新机制原理

nacos动态配置刷新机制原理 项目里面许多业务场景以及灵活配置的需求经常要用到动态配置。一般就是apollo和nacos两种选型。 nacos动态刷新导致的bug nacos一般为了实现动态配置一般会加入RefreshScope注解进行实现&#xff0c;例如下面的代码加入了RefreshScope想要实现跨域…

智能家居监控管理系统项目需求分析

目录 一、引言 1、目的 2、背景 二、项目系统概述 1、项目产品概述 2、项目功能架构 3、项目市场需求 三、项目硬件需求 1、核心开发板 2、实时检测模块 3、实时信息交互模块 4、用户安全登录模块 5、开发板可扩展模块 6、硬件之间连接设备 四、项…

网络安全进阶学习第二十课——CTF之文件操作与隐写

文章目录 一、文件类型识别1、File命令2、Winhex3、文件头残缺/错误 二、文件分离操作1、Binwalk工具2、Foremost3、dd4、Winhex 三、文件合并操作1、Linux下的文件合并2、Windowsa下的文件合并 四、文件内容隐写Winhex 五、图片文件隐写1、图片混合2、LSB(最低有效位 Least Si…

slickEdit 2022 (v27.0.2)Ubuntu安装以及破解

1去官网下载安装包 SlickEdit 也可以从我这里下载源码包 https://download.csdn.net/download/m0_38012470/88343180 2.解压压缩包并进入根目录 3.sudo ./vsinst 4按住回车不松手一直到显示需要你输入yes的时候 5.一路通过需要输入Y的时候就输入 6.一直到弹出对话框关闭…

c++11的一些新特性

c11 1. {}初始化2. 范围for循环3. final与override4. 右值引用4.1 左值引用和右值引用4.2 左值引用与右值引用比较 5. lambda表达式6. 声明6.1 auto6.2 decltype6.3 nullptr 7. 可变参数模版 1. {}初始化 在C中&#xff0c;使用花括号初始化的方式被称为列表初始化。列表初始化…

Windows C++ 环境下 eigen、osqp、osqp-eigen安装教程

本文是Windows环境下安装eigen、osqp、osqp-eigen的一个简单教程。 osqp是用于二次规划的一种求解器&#xff0c;提供包括C、Matlab、Python等在内的接口&#xff0c;但是不包含C接口。为了能在C 中使用osqp&#xff0c;可以使用osqp-eigen接口进行调用。 第一步&#xff1a;…

第二章 进程与线程 七、处理机调度(概念、层次)

目录 一、基本概念 二、三个层次 1、高级调度&#xff08;作业调度&#xff09; 2、低级调度&#xff08;进程调度/处理机调度&#xff09; 3、中级调度&#xff08;内存调度&#xff09; 三、三次调度的联系、对比 四、七状态模型 五、总结 一、基本概念 当有一堆任务…

利用群论来研究魔方

文章灵感来源于&#xff1a; 魔方与群论&#xff08;二&#xff09;&#xff08;交换子牛啤&#xff01;&#xff09; - 知乎并参考了&#xff1a;https://www.gap-system.org/Doc/Examples/rubik.html使用了这里的小程序&#xff1a;Cubie 先汇制一张&#xff0c;魔方图 ----…

MySQL数据库upsert使用

本文翻译自&#xff1a;MySQL UPSERT - javatpoint&#xff0c;并附带自己的一些理解和使用经验. MySQL UPSERT UPSERT是数据库管理系统管理数据库的基本功能之一&#xff0c;它允许数据库操作语言在表中插入一条新的数据或更新已有的数据。UPSERT是一个原子操作&#xff0c;…

手刻 Deep Learning -第壹章-PyTorch入门教学-基础概念与再探线性回归

一、前言 本章会需要 微分、线性回归与矩阵的基本观念 这次我们要来做 PyTorch 的简单教学&#xff0c;我们先从简单的计算与自动导数&#xff08; auto grad / 微分 &#xff09;开始&#xff0c;使用优化器与误差计算&#xff0c;然后使用 PyTorch 做线性回归&#xff0c;还有…