【Java】TCP网络编程(字节/符流)

news2024/9/21 18:33:01

在这里插入图片描述

文章目录

  • 概念
  • TCP网络编程
  • ServerSocket
  • socket
  • 使用区别和原理演示

概念

TCP(传输控制协议)是一种面向连接的协议,用于在计算机网络中可靠地传输数据。TCP是Internet协议族中的一个核心协议,它在传输层提供可靠、有序、基于流的传输服务。

网络编程是使用计算机网络进行编程的过程,可以使用各种编程语言和协议来实现网络通信。TCP网络编程是指使用TCP协议进行网络通信的编程技术。

TCP网络编程

TCP网络编程有两种模式,一种是服务器模式,另一种是客户端模式。服务器模式创建一个服务程序,等待客户端用户的连接,接收到用户的连接请求后,根据用户的请求进行处理;客户端模式则根据目的服务器的地址和端口进行连接,向服务器发送请求并对服务器的响应进行数据处理。

ServerSocket类和socket类(服务端/客户端)实现了基于TCP协议网络程序


客户端程序发起连接,形成数据通道,发给信息给服务端;服务器端在某个端口进行监听(这里以9999端口作为演示),当客户端连接到服务端后,实际上客户端是通过一个端口和服务端进行通讯的,这个端口是TCP/IP分配的(服务端通信的端口是固定的)

服务端
1.在本机的9999端口监听,等待连接
2.当没有客户端连接9999端口时,程序会阻塞,等待连接
3.通过socket.getInputStream()方法来读取客户端写入到通道的数据
客户端
1.连接服务端(IP,端口)
2.连接上后,会生成Socket,通过socket.getOutputStream()
3.通过输出流,写入数据到数据通道

ServerSocket

在客户/服务器通信模式中,服务器端需要创建监听特定端口的ServerSocket,ServerSocket负责接收客户连接请求。(用于监听端口)

该类提供了四个构造器,根据不同的场景进行选择
在这里插入图片描述
常用方法

  • accept():侦听并接受此套接字的连接;当有客户端连接的时候会返回一个Socket对象。此方法在连接传入之前一直阻塞

此代码执行之后,只会输出服务端在9999端口监听等待连接,而后一直阻塞等待(只有返回socket对象之后才会继续)

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketTCP01Server {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(9999);
            System.out.println("服务端在9999端口监听等待连接");
            Socket socket = serverSocket.accept();
            System.out.println("服务器端:"+socket.getClass());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

注意:要求被监听的端口没有被其他服务或程序占用,否则会出异常

socket

这个类实现了客户端套接字(也被称为“套接字”)。套接字是两台机器之间的通信的一个端点。 用于客户端与服务端之间的连接,如果连接成功返回Socket对象

该类提供了9个构造器,根据不同的场景进行选择
在这里插入图片描述
这里使用常用的Socket(InetAddress address, int port) 作为演示

  • address:IP地址
  • port:端口号

常用方法

  • getInputStream():返回socket的输入流,用于接收数据
  • getOutputStream:返回socket的输出流,用于发送数据
  • shutdownOutput():表示一个Output结束标记,表示后面没有要输入的东西
  • shutdownInput():表示一个Input结束标记,表示后面没有要读的数据了

通常Socket构造器中的IP地址写的是远程服务器的IP地址,这里作为演示使用本机IP

InetAddress.getLocalHost();//获取本机IP

此时先执行ServerSocket中监听指定端口(代码在ServerSocket中),然后执行下列代码,会连接成功

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;

public class SocketTCP01Client {
    public static void main(String[] args) {
        try {
            //连接本机的9999端口
            Socket socket = new Socket(InetAddress.getLocalHost(),9999);
            System.out.println("客户端:连接成功"+socket.getClass());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户端和服务端各有一个Socket对象

使用区别和原理演示

区别
当serverSocket.accept()时,可以返回多个socket对象(多并发)一台计算机可以同时提供多个服务,这些不同的服务之间通过端口号来区别,不同的端口号上提供不同的服务。当多个服务(服务器)连接同一个端口时,accept之后会返回多个socket对象

工作原理

  1. 服务端:监听端口,等待连接
  2. 客户端:连接服务端端口,返回Socket对象,同时服务端也返回Socket对象
  3. 客户端:连接上后,通过socket.getOutputStream()得到socket对象关联的输出流对象
  4. 客户端:通过输出流,写入数据
  5. 服务端:通过socket.getInputStream()读取客户端写入到数据通道的数据,并输出
  6. 客户端和服务端:socket和流进行关闭(close),避免造成资源浪费

代码演示
理论上服务端和客户端的程序应该是在不同的机器上的,这里为了方便,使用了一台机器(可以自行设置虚拟机)

1.客户端连接到服务端,发送hello server并退出;服务端接收到客户端的信息,打印并退出

以下代码执行过后,服务端会输出客户端发来的信息,先执行服务端,在执行客户端。如果出现异常,可以把电脑防火墙关闭

这里使用的String类中getBytes方法(字符串转字节数组)和String的构造器
在这里插入图片描述

服务端

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketTCP01Server {
    public static void main(String[] args) {
        InputStream inputStream = null;
        Socket socket = null;
        try {
            ServerSocket serverSocket = new ServerSocket(9999);
            System.out.println("服务端在9999端口监听等待连接");
            socket = serverSocket.accept();
            inputStream = socket.getInputStream();
            byte[] bytes = new byte[1024];
            int len =0;
            while ((len=inputStream.read(bytes))!=-1){
                System.out.println(new String(bytes,0,len));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                socket.close();
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

客户端

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

public class SocketTCP01Client {
    public static void main(String[] args) {
        Socket socket = null;
        OutputStream outputStream = null;
        try {
            socket = new Socket(InetAddress.getLocalHost(),9999);
            System.out.println("客户端:连接成功"+socket.getClass());
            outputStream = socket.getOutputStream();
            outputStream.write("hello,server".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                socket.close();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

2.客户端连接到服务端,发送hello,server,并接收服务端回发的hello,client并退出;服务端接收到客户端的信息,输出并退出

注意:在发送完一个数据的时候,需要有一个结束标记,表示该数据发送完毕,可以发送下一个,要不然当多个数据发送时,会出现死锁的情况。

服务端

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketTCP02Server {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        InputStream inputStream = null;
        Socket socket = null;
        OutputStream outputStream = null;
        try {
            serverSocket = new ServerSocket(9999);
            System.out.println("服务端在9999端口监听等待连接");
            socket = serverSocket.accept();
            inputStream = socket.getInputStream();
            byte[] bytes = new byte[1024];
            int len = 0;
            System.out.println("客户端发的信息为:");
            while ((len = inputStream.read(bytes)) != -1) {
                System.out.println(new String(bytes, 0, len));
            }
            socket.shutdownInput();//表示一个结束标记
            outputStream = socket.getOutputStream();
            outputStream.write("hello,client".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                socket.close();
                inputStream.close();
                outputStream.close();
                serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

客户端

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

public class SocketTCP02Client {
    public static void main(String[] args) {
        Socket socket = null;
        OutputStream outputStream = null;
        InputStream inputStream = null;
        try {
            socket = new Socket(InetAddress.getLocalHost(),9999);
            System.out.println("客户端:连接成功"+socket.getClass());
            outputStream = socket.getOutputStream();
            outputStream.write("hello,server".getBytes());
            socket.shutdownOutput();//表示一个结束标记
            inputStream = socket.getInputStream();
            byte[] buf = new byte[1024];
            int readlen = 0;
            System.out.println("服务端发的信息为:");
            while ((readlen = inputStream.read(buf))!=-1){
                System.out.println(new String(buf,0,readlen));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                socket.close();
                outputStream.close();
                inputStream.close();
                System.out.println("客户端退出");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

3.使用TCP字符流完成网络数据通讯演示(这里使用了转换流,把字节流转换为字符流),如果使用字符流需要手动刷新,调用flush方法,否则数据不会写入

注意:newLine()也可以是设置写入标记(换行符),需要对方使用readLine():读取结束标记才可以

服务端

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketTCP03Server {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        InputStream inputStream = null;
        Socket socket = null;
        OutputStream outputStream = null;
        BufferedWriter bufferedWriter = null;
        try {
            serverSocket = new ServerSocket(9999);
            System.out.println("服务端在9999端口监听等待连接");
            socket = serverSocket.accept();
            inputStream = socket.getInputStream();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            System.out.println(bufferedReader.readLine());
//            socket.shutdownInput();//表示一个结束标记
            outputStream = socket.getOutputStream();
            bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
            bufferedWriter.write("hello,client字符流");
            bufferedWriter.newLine();//结束标记
            bufferedWriter.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                socket.close();
                serverSocket.close();
                bufferedWriter.close();//关闭外层流即可
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

客户端

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

public class SocketTCP03Client {
    public static void main(String[] args) {
        Socket socket = null;
        OutputStream outputStream = null;
        InputStream inputStream= null;
        BufferedReader bufferedReader = null;
        try {
            socket = new Socket(InetAddress.getLocalHost(),9999);
            System.out.println("客户端:连接成功"+socket.getClass());
            outputStream = socket.getOutputStream();
            
            BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
            bufferedWriter.write("hello,server字符流");
            bufferedWriter.newLine();//换行符,在这里表示结束标记
            bufferedWriter.flush();
//            socket.shutdownOutput();//表示一个结束标记
            inputStream = socket.getInputStream();
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            System.out.println(bufferedReader.readLine());
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                socket.close();
                bufferedReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

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

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

相关文章

影视网络U盘系统开发思路

由于光纤入户千兆宽带的普及,在用户侧的下载速度得到前所未有的提高。与此同时,用户对于高清视频的需求日益增强,原有的视频点播系统在传输高清视频码流上时有卡顿现象发生,这严重影响了用户的娱乐体验。现时,大部分用…

IOS逆向之frida安装

首先手机要越狱,这个就不说了,博主就是咸鱼搞了个160的苹果6, 自己刷到苹果6支持最新的12.5.7版本后越狱; 谁让他低版本,不支持 CrackerXI砸壳呢,当时你要是使用 frida-ios-dump 也是可以的; …

【MySQL之SQL语法篇】系统学习MySQL,从应用SQL语法到底层知识讲解,这将是你见过最完成的知识体系

文章目录一、数据管理技术的三个阶段二、SQL语句学习1. DCL数据控制语言1.1 创建用户1.2 修改用户名1.3 修改密码1.4 删除用户1.5 授权1.6 查看权限1.7 回收权限2. DDL数据定义语言2.1 操作数据库2.2 操作数据表2.3 操作数据3. DQL数据查询语言基本语法3.1 单表查询3.1.1选择表…

Linux基础命令-ln创建链接文件

文章目录 ln 命令介绍 命令格式 基本参数 参考实例 1) 创建文件的硬链接 2)创建文件的软链接 3)创建链接文件时,相同目标文件创建备份文件 命令总结 ln 命令介绍 先看下帮助文档中的含义 NAME ln - make links …

HTML标签——表单标签

HTML标签——表单标签 目录HTML标签——表单标签一、input系列标签1.文本框(拓展)value属性和name属性作用介绍2.单选框3.复选框4.文件选择二、select下拉菜单标签三、label标签一、input系列标签 1.文本框 场景:在网页中显示输入单行文本的…

FL studio2023体验版及切换水果中文语言切换教程

FL studio2023提供了试用版本可供使用,功能和入门版的功能一样,但是有个缺点是不能够保存。只能当下做完,马上输出。入门版没有提供Audio音频编辑和录制的功能,建议要下手可以从完整版本去考虑。因为就算现在没有要录音&#xff0…

【Leedcode】栈和队列必备的面试题(第一期)

栈和队列必备的面试题(第一期) 文章目录栈和队列必备的面试题(第一期)一、题目二、思路(图解)三、存在的问题与隐患(报错提示)(1)s中只有右括号,无…

Capture Modules:车载网络报文捕获模块

(以下所有图片均来源于Technica官网) Technica Engineering的新一代硬件设备,即Capture Modules,提供了五种变体以涵盖不同带宽的车载以太网(100BASE-T1和1000BASE-T1)以及常见的IVN技术(CAN、C…

云原生架构基础概念及应用办法

什么是云原生? 云原生是一种基于容器、微服务和自动化运维的软件开发和部署方法。它可以使应用程序更加高效、可靠和可扩展,适用于各种不同的云平台。 如果要更直接通俗的来解释下上面的概念。 云原生更准确来说就是一种文化,是一种潮流&a…

modbus转profinet网关连接UV系列流量计程序实例

用户现场是西门子1200PLC通过兴达易控Modbus转Profinet网关连接流量计的配置,对流量瞬时值及报警值监控及控制程序案例 硬件连接兴达易控网关采用Profinet双网口,一端连接PLC、一端连接编程软件,单路485接口连接流量计,对流量值实…

mac使用sublime text卡顿解决方法,附常用快捷键

在mac上使用sublime text总是卡顿,比如选中一段文字复制,然后去干别的,等会回来点击空白处取消对文字的选择,点好多下都取消不了。 再比如修改tab格式也是改着改着就卡住了。 解决方法也很简单,打开sublime text的配置…

MIT:只需一层RF传感器,就能为AR头显赋予“X光”穿透视力

近年来,AR在仓库、工厂等场景得到应用,比如GlobalFoundries、亚马逊、菜鸟裹裹就使用摄像头扫描定位货品,并使用AR来导航和标记。目前,这种方案主要基于视觉算法,因此仅能定位视线范围内的目标。然而,在一些…

python基础—字符串操作

(1)字符串: Python内置了一系列的数据类型,其中最主要的内置类型是数值类型、文本序列(字符串)类型、序列(列表、元组和range)类型、集合类型、映射(字典)类型…

论文阅读 | Cross-Attention Transformer for Video Interpolation

前言:ACCV2022wrokshop用transformer做插帧的文章,q,kv,来自不同的图像 代码:【here】 Cross-Attention Transformer for Video Interpolation 引言 传统的插帧方法多用光流,但是光流的局限性在于 第一&…

Android Qcom Audio架构学习

总结: Android Audio不简单呀,一个人摸索入门不容易的,研究了一段时间,感觉还不是很懂,但以下的知识对入门还是有帮助的。 Audio架构中的名词 FE(Front End) 提供pcm的设备信息,将数据从用户空间传输到音…

【大数据离线开发】8.2 Hive的安装和配置

8.3 Hive的安装和配置 安装模式: 嵌入模式 :不需要使用MySQL,需要Hive自带的一个关系型数据库:Derby本地模式、远程模式 ----> 需要MySQL数据库的支持 安装 hive 安装包 1、解压tar -zxvf apache-hive-2.3.0-bin.tar.gz -C…

美格智能发布高性价比5G CPE解决方案SRT838I,赋能5G FWA行业数字化转型

2月27日,在MWC 2023世界移动通信大会上,美格智能重磅发布高性价比5G CPE解决方案SRT838I,该方案搭载高通骁龙X62调制解调器及射频系统WCN6856高速5G解决方案设计,其具有广覆盖、强信号、高速率等特点,非常符合5G CPE的…

.NET 导入导出Project(mpp)以及发布后遇到的Com组件问题

最近公司项目有一个对Project导入导出的操作,现在市面上能同时对Project进行导入导出的除了微软自带的Microsoft.Office.Interop.MSProject,还有就是Aspose.Tasks for .NET。但因为后者是收费软件且破解版的现阶段只到18.11,只支持.net Frame…

【博学谷学习记录】超强总结,用心分享丨人工智能 多场景实战 常用英文缩写概念总结

目录PV(Page View)UV(Unique Visitor)CPM(Cost Per Mille)CPC(Cost Per Click)CPA(Cost Per Action)CPI(Cost Per Install)ACU(Average concurrent users)PCU(Peak concurrent users)ARPU(Average Revenue Per User)ARPPU(Average Revenue Per Paying User)LTV(Life Time Value…

Windows系统部署瀚高数据库并在SuperMap iDesktop中使用

目录前言一:Windows系统部署瀚高数据库二:对数据库进行PostGIS扩展三:SuperMap iDesktop中新建HighGoDB数据库型数据源作者:kxj 前言 瀚高数据库是一款对象-关系型数据库,拥有非常丰富的数据库基本功能,涵盖…