使用Socket技术进行数据传输、传输文件;浏览器访问Socket服务器

news2024/9/21 15:52:52

文章目录

    • 计算机网络基础
      • IP地址和端口
      • TCP和 UDP
    • Socket技术
    • 使用Socket进行数据传输
    • 使用Socket传输文件
    • 使用浏览器访问Socket服务器

计算机网络基础

利用通信线路和通信设备,将地理位置不同的、功能独立的多台计算机互连起来,以功能完善的网络软件来实现资源共享和信息传递,就构成了计算机网络系统

IP地址和端口

通过IP地址,区分不同的计算机

每一台电脑在一个网络上拥有一个独属于自己的IP地址,用于区别其他电脑,可以通过对方的IP地址进行访问;所以当我们的手机开着流量的时候,是无法访问连着WIFI的电脑的

电脑上运行的大量程序可能需要通过网络来访问其他计算机,这时通过端口号来进行区分

image-20230513220614495

因此一般看到的是地址都是IP:port形式访问目标主机的一个应用程序,端口号的值为[0, 65535]

IP地址分为IPv4和IPv6,IPv4类似于192.168.0.11,上面提到的例子都是使用的IPv4,它一共有四组数字,每组数字占8个bit位,IPv4地址0.0.0.0表示为2进制就是:00000000.00000000.00000000.00000000,共32个bit,最大为255.255.255.255

IPv6能够保存128个bit位,因此它也可以表示更多的IP地址,一个IPv6地址看起来像这样:1030::C9B4:FF12:48AA:1A2B,目前也正在向IPv6的阶段过渡

TCP和 UDP

  • TCP:当一台计算机想要与另一台计算机通讯时,两台计算机之间的通信需要畅通且可靠(会进行三次握手,断开也会进行四次挥手),这样才能保证正确收发数据,因此TCP更适合一些可靠的数据传输场景
  • UDP:它是一种无连接协议,数据不会建立可靠传输,传输过程中有可能会导致部分数据丢失,但是它比TCP传输更加简单高效,适合视频直播之类的

image-20230513220851141

Socket技术

通过Socket技术(它是计算机之间进行通信一种约定或一种方式),可以实现两台计算机之间的通信,Socket也被翻译为套接字,是操作系统底层提供的一项通信技术,它支持TCP和UDP。而Java就对socket底层支持进行了一套完整的封装,因此可以通过Java来实现Socket通信。

要实现Socket通信,需创建一个数据发送者和一个数据接收者,也就是客户端和服务端,我们需要提前启动服务端,来等待客户端的连接,而客户端只需要随时启动去连接服务端即可

//服务端
public static void main(String[] args) {
    try(ServerSocket server = new ServerSocket(8080)){    //将服务端创建在端口8080上
        System.out.println("正在等待客户端连接...");
        Socket socket = server.accept();  //当没有客户端连接时,线程会阻塞,直到有客户端连接为止
        System.out.println("客户端已连接,IP地址为:"+socket.getInetAddress().getHostAddress());
    }catch (IOException e){
        e.printStackTrace();
    }
}

用户端

public static void main(String[] args) {
    try (Socket socket = new Socket("localhost", 8080)){
        System.out.println("已连接到服务端!");
    }catch (IOException e){
        System.out.println("服务端连接失败!");
        e.printStackTrace();
    }
}

实际上他是一个TCP连接的过程,一旦连接建立,只要客户端不主动关闭,整个程序就不会停止运行;服务端也不仅仅支持一个客户端,在同一网络的前提下,可以连接多个服务端

public static void main(String[] args) {
	try(ServerSocket server = new ServerSocket(8080)) { //port,也就是端口号为8080
        System.out.println("等待连接...");
        while(true) {
            Socket s = server.accept(); //无限循环等待客户端的连接
            System.out.println("IP地址为:" + socket.getInetAddress().getHostAddress());
        }
    }catch(IOException e) {
        e.printStackTrace();
    }
}

使用Socket进行数据传输

通过Socket对象,我们就可以获取到对应的I/O流进行网络数据传输:

服务端

//Server端
public class server {
    public static void main(String[] args) {
        try(ServerSocket server = new ServerSocket(8080)){ //try-with-resource语句,自动关闭,不需要close
            System.out.println("正在等待客户端连接:");
            Socket socket = server.accept();
            socket.setSoTimeout(5000); // timeout
            System.out.println("客户端已连接,IP地址为:" + socket.getInetAddress().getHostAddress());
            System.out.println("读取客户端数据:");
            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            System.out.println("内容为:" + reader.readLine());

            OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream());
            writer.write("收到\n");
            writer.flush();
            socket.close();
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

用户端

public class Main {
    public static void main(String[] args) {
        try(Socket s = new Socket("localhost", 8080);
            Scanner sc = new Scanner(System.in)){
            System.out.println("已连接到服务区");
            OutputStreamWriter writer = new OutputStreamWriter(s.getOutputStream()); //读取发送内容
            writer.write(sc.nextLine() + "\n"); //加换行符是读取需要
            writer.flush();
            s.shutdownOutput();
            System.out.println("数据已发送");

            BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream()));
            System.out.println("收到服务端响应:" + reader.readLine());
        }catch(IOException e) {
            System.out.println("连接失败");
            e.printStackTrace();
        }finally {
            System.out.println("断开连接");
        }
    }
}

先启动Server端,再启动用户端;127.0.0.1是自己电脑

image-20230513204331818 image-20230513204351867

手动关闭单向的流:

socket.shutdownOutput(); //输出方向关闭
socket.shutdownInput(); //关闭输入方向

可以通过调用setSoTimeout()方法来设定IO超时时间:

socket.setSoTimeout(3000);

当超过设定时间都依然没有收到客户端或是服务端的数据时,会抛出异常:

java.net.SocketTimeoutException: Read timed out
	at java.net.SocketInputStream.socketRead0(Native Method)
	at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
	at java.net.SocketInputStream.read(SocketInputStream.java:171)
	at java.net.SocketInputStream.read(SocketInputStream.java:141)
	at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
	at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
	at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
	at java.io.InputStreamReader.read(InputStreamReader.java:184)
	at java.io.BufferedReader.fill(BufferedReader.java:161)
	at java.io.BufferedReader.readLine(BufferedReader.java:324)
	at java.io.BufferedReader.readLine(BufferedReader.java:389)
	at com.test.Main.main(Main.java:41)

也可以不自动链接

try (Socket socket = new Socket();
	Scanner sc = new Scanner(System.in)) {
		socket.connect(new InetSocketAddress("localhost", 8080), 1000);
	}

可能会出现连接双方出现意外却通知不到对方的情况,这个时候其中一方还持有联系,就会占用资源,可以使用setKeepAlive()的方法来防止:

socket.setKeepAlive(true);

当客户端连接之后,如果此函数设置值为true,当对方没有发送任何数据过来的时候,超过一个时间(要看系统内核参数配置),这边就会发送一个ack探测包,探测TCP/IP连接是否有效

100%弄明白5种IO模型 - 知乎

此缓冲区大小为:8192,我们可以手动调整其大小来优化传输效率:

socket.setReceiveBufferSize(25565);   //TCP接收缓冲区
socket.setSendBufferSize(25565);    //TCP发送缓冲区

使用Socket传输文件

实现文件传输

用户端

public class Main {
    public static void main(String[] args) {
        try(Socket s = new Socket("localhost", 8080)){
            FileInputStream fis = new FileInputStream("test.txt"); //输入文件
            OutputStream stream = s.getOutputStream(); //输出流
            byte[] bytes = new byte[1024];
            int len;
            while((len = fis.read(bytes)) != -1) {
                stream.write(bytes, 0, len);
            }
            fis.close();
            stream.flush();
            stream.close();
            System.out.println("文件已传输");
        }catch(IOException e) {
            System.out.println("连接失败");
            e.printStackTrace();
        }
    }
}

服务端

public class server {
    public static void main(String[] args) {
        try(ServerSocket server = new ServerSocket(8080)){
            Socket socket = server.accept();

           InputStream stream = socket.getInputStream();
           FileOutputStream file = new FileOutputStream("toserver.txt");
           byte[] buffer = new byte[1024];
            int len;
            while((len = stream.read(buffer)) != -1){
                file.write(buffer, 0, len);
            }
            file.flush();
            file.close();
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

使用浏览器访问Socket服务器

public class server {
    public static void main(String[] args) {
        try(ServerSocket server = new ServerSocket(8080)){
            System.out.println("正在等待客户端连接:");
            Socket socket = server.accept();
            System.out.println("IP地址为:" + socket.getInetAddress().getHostAddress());
            InputStream in = socket.getInputStream();
            while(true) {
                int read = in.read();
                if(read == -1) {
                    break;
                }
                System.out.print((char) read);
            }
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

启动Server端,用浏览器输入http://localhost:8080或是http://127.0.0.1:8080/访问;会发现浏览器无法访问,但是IDEA给了一堆反馈

image-20230513214310166

我们的服务端能够读取HTTP请求。但是Http协议并不会保持长连接,在得到我们响应的数据后会立即关闭TCP连接。

既然使用的是Http连接,如果我们的服务器要支持响应HTTP请求,那么就需要按照HTTP协议的规则,返回一个规范的响应文本,首先是响应头,它至少要包含一个响应码:

HTTP/1.1 200 Accpeted

然后就是响应内容(注意一定要换行再写),我们尝试来编写一下支持HTTP协议的响应内容:

public static void main(String[] args) {
    try(ServerSocket server = new ServerSocket(8080)){
        System.out.println("正在等待客户端连接...");
        Socket socket = server.accept();
        System.out.println("客户端已连接,IP地址为:"+socket.getInetAddress().getHostAddress());
        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
        System.out.println("接收到客户端数据:");
        while (reader.ready()) System.out.println(reader.readLine()); 
        OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream());
        writer.write("HTTP/1.1 200 Accepted\r\n");   //200是响应码,Http协议规定200为接受请求,400为错误的请求,404为找不到此资源(不止这些,还有很多)
        writer.write("\r\n");   //在请求头写完之后还要进行一次换行,然后写入响应实体(会在浏览器上展示的内容)
        writer.write("You're on your own Kids!");
        writer.flush();
    }catch (Exception e){
        e.printStackTrace();
    }
}

我们可以打开浏览器的开发者模式,我们来观察一下浏览器的实际请求过程。
image-20230513220047808

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

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

相关文章

Visual Studio 2022 v17.6 正式发布

Visual Studio 17.6 正式发布,这个最新版本提供了一系列强大的工具和功能,旨在使你能够制作出最先进的应用程序。 提高生产力 通过 Visual Studio 2022,目标是帮助你在更短的时间内完成 IDE 内的所有开发任务,在这个版本中&…

Vue3 QQ登录

Vue3 QQ登录 开发前需要去 QQ互联平台申请认证&#xff0c;创建应用 拿到对应的APPID、APPKey 一、引用QQjsdk 1、可直接引用 QQjsdk //绑定对应的APPID跟页面回调地址 <script type"text/javascript" charset"utf-8" src"https://connect.qq…

图像识别和计算机视觉:如何应用人工智能技术实现自动化检测和识别

章节一&#xff1a;引言 在数字化时代&#xff0c;图像数据成为了我们日常生活中不可或缺的一部分。然而&#xff0c;随着图像数据的急剧增加&#xff0c;传统的手动处理和分析方法已经无法满足我们的需求。这就引出了图像识别和计算机视觉技术的重要性。本文将介绍人工智能技…

程序员降薪40%去国企,只因要35岁了!值得吗?

说到程序员&#xff0c;大家首先想到的就是“高薪”&#xff0c;“有实力”&#xff0c;程序员是个比较吃香的职业&#xff0c;发展前景和薪资待遇都非常可观。 但是在程序员的世界里&#xff0c;一直有一个传言&#xff0c;35岁是技术人的天花板。这个观点&#xff0c;无意中…

君正X2000 Linux SDK

一、测试所用的硬件 深圳君正开发板&#xff1a;PD_X2000_EVB_CORE_V1P1 二、SDK源码下载 参考君正官方教程&#xff1a;君正全平台linux源码同步教程&#xff08;除X1830人脸识别板&#xff09;_君正a1n linux_北京君正的博客-CSDN博客 教程中要求的系统为Ubuntu20.4&#…

批量提取某音文案

牙叔教程 简单易懂 我想学习某个人的文案, 怎么把它的文案全下载下来? 批量下载视频和音频批量音频转文字 下载视频和音频 我在github找到的是这个仓库 GitHub - Johnserf-Seed/TikTokDownload: 抖音去水印批量下载用户主页作品、喜欢、图文、音频 经过实际测试, 可以使用,…

[FMC149】基于VITA57.1标准的16通道65MSPS 14位直流耦合AD采集FMC子卡

板卡概述 FMC149是一款16通道65MHz采样率14位直流耦合AD采集FMC子卡&#xff0c;符合VITA57.1规范&#xff0c;可以作为一个理想的IO模块耦合至FPGA前端&#xff0c;16通道AD通过FMC连接器&#xff08;HPC&#xff09;连接至FPGA从而大大降低了系统信号延迟。 该板卡支持板上可…

【STL】vector的模拟实现

目录 前言 结构解析 构造析构 构造 默认构造 初始化成 n 个 val 以迭代器区间构造 拷贝构造 析构 运算符重载 赋值重载 下标访问 迭代器 const迭代器 容量操作 查看大小和容量 容量修改 数据修改 尾插尾删 指定位置插入和删除 insert erase 清空 判空 …

Redis系列--主从复制

一、redis主从复制介绍 在 Redis 复制的基础上&#xff0c;使用和配置主从复制非常简单&#xff0c;能使得从 Redis 服务器&#xff08;下文称 slave&#xff09;能精确得复制主 Redis 服务器&#xff08;下文称 master&#xff09;的内容。每次当 slave 和 master 之间的连接断…

chatGpt 对前端的开发帮助

chatGpt 是 什么&#xff1f; ChatGPT是一个基于GPT-3的聊天机器人&#xff0c;可以用来帮助前端开发人员解决各种问题。它可以回答关于前端开发的各种问题&#xff0c;包括HTML、CSS、JavaScript、React、Vue等等。它可以提供代码片段、示例代码、文档链接等等&#xff0c;帮助…

javascript 创建 array

javascript 创建 array 补一下笔记&#xff0c;constructor 这块之前还真没怎么太琢磨过…… 最常见的就是 literal array syntax: const arr1 [1, 2, 3];console.log(arr1);这是最主流的用法&#xff0c;也是目前最推荐的用法&#xff0c;原因有以下几点&#xff1a; 这是…

SOLIDWORKS 30个使用技巧

很多人在学习SolidWorks时&#xff0c;会有很多疑问&#xff0c;都不知道如何解答&#xff0c;所以走了很多弯路。今天&#xff0c;我们就来讲讲在学习SolidWorks中的那些小技巧吧&#xff01; 1、按“空格键&#xff1a;”弹出快捷菜单双击某一视图&#xff0c;模型将转向某一…

3分钟带你入门接口自动化测试(建议收藏)

接口测试简介 1&#xff09; 什么是接口测试 开始学习接口自动化测试之前&#xff0c;我们先要来了解什么是接口&#xff0c;以及什么是接口测试。 我们都知道&#xff0c;测试从级别上划分可以分为 ◆ 组件测试 ◆ 集成测试 ◆ 系统测试 ◆ 验收测试 其中在集成测试这个…

Vue3系列——computed、watch

目录 Computed watch 侦听单个数据 侦听多个数据 immediate deep 精确侦听对象的某个属性 Computed 计算属性computed是依赖于使用它的数据&#xff0c;当数据发生变化时&#xff0c;自定义方法重新调用执行一次计算属性&#xff0c;监测的是依赖值&#xff0c;依赖值不…

GPT专业应用:生成会议通知

正文共 917 字&#xff0c;阅读大约需要 3 分钟 公务员/文秘必备技巧&#xff0c;您将在3分钟后获得以下超能力&#xff1a; 快速生成会议通知 Beezy评级 &#xff1a;B级 *经过简单的寻找&#xff0c; 大部分人能立刻掌握。主要节省时间。 推荐人 | Kim 编辑者 | Linda ●图…

Qt6之万能数据类型QVariant详解

QVariant&#xff0c;被称为万能数据类型&#xff0c;实际上它是类似C的联合union类型。简单的说自定义性能强就像一个盒子几乎可以让你放任意的qt类型&#xff0c;同时可以轻松构造任意类型的任意复杂数据结构&#xff0c;但请注意复杂类型意味着性能和效率的让步。 qt6在文档…

好的CRM系统拥有哪些功能

随着客户对企业的重要性越来越高&#xff0c;他们需要一款好用的CRM系统来帮助他们管理客户、销售管道和营销活动。那么国内目前比较好的CRM系统有哪些&#xff1f;下面我们来详细说一下。 国内有很多知名的CRM系统&#xff0c;从本土品牌到国际厂商都有。选择 CRM以高性价比、…

永久免费域名PP.UA最新注册指南

PP.UA是乌克兰个人的域名&#xff0c;支持CF托管&#xff0c;可用于建站或者个人代理用&#xff0c;其永久免费&#xff08;每年续期即可&#xff09;。不过网上关于这个免费域名的申请教程已经全部过期了&#xff0c;多数都是2021年的&#xff0c;本次我来做一个最新的可用教程…

【Redis】Redis 命令之 String

文章目录 ⛄String 介绍⛄命令⛄对应 RedisTemplate API⛄应用场景 ⛄String 介绍 String 类型&#xff0c;也就是字符串类型&#xff0c;是Redis中最简单的存储类型。 其value是字符串&#xff0c;不过根据字符串的格式不同&#xff0c;又可以分为3类&#xff1a; ● string&…

flutter系列之:使用AnimationController来控制动画效果

文章目录 简介构建一个要动画的widget让图像动起来总结 简介 之前我们提到了flutter提供了比较简单好用的AnimatedContainer和SlideTransition来进行一些简单的动画效果&#xff0c;但是要完全实现自定义的复杂的动画效果&#xff0c;还是要使用AnimationController。 今天我…