Java编程-TCP(Java编程软件)
wptr33 2024-11-16 01:28 23 浏览
1.1. Java的TCP
面向连接, 数据安全, 区分服务器端和客户端.
TCP分为Socket(客户端)和ServerSocket(服务端)
需要分别建立客户端和服务器端
客户端和服务端建立连接后,通过Socket中的IO流进行数据的传输
需要关闭关闭socket
同样,客户端与服务器端是两个独立的应用程序。
1.1.1. TCP客户端
第一步:创建客户端Socket
需要指定连接到服务器的地址和端口号, 并尝试连接
客户端需要明确服务器的ip地址以及端口,这样才可以去试着建立连接,如果连接失败,会出现异常。
Socket socket = new Socket("192.168.1.220", 8888); |
第二步:连接成功获取输入输出流
连接成功,说明客户端与服务端建立了通道,那么通过IO流就可以进行数据的传输,而Socket对象已经提供了输入流和输出流对象,通getInputStream(),getOutputStream()获取即可。
socket.getInputStream(); socket.getOuputStream(); |
第三步: 将数据写出到服务端
使用字节输出流的write() 方法 |
第四步:关闭socket
调用close方法 |
连接成功之后获取输入输出流
socket.getInputStream();
socket.getOuputStream();
获取流之后就可以通过输入输出流发送和读取数据了, 客户端的输入流连接服务端输出流, 客户端输出流连接服务端输入流
客户端案例: public class TcpClient { public static void main(String[] args) throws IOException, IOException { System.out.println("客户端启动..."); // 创建客户端 Socket socket = new Socket("127.0.0.1", 50000); // 与服务端建立连接,获取输入输出流 InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); // 将数据写出到服务端 System.out.println("客户端发送数据..."); out.write("Tcp,你好我是客户端...".getBytes()); // 关闭socket out.close(); } } |
1.1.2. TCP服务端:
第一步: 创建服务端
ServerSocket, 需要指定端口号. 客户端连接的就是这个端口.
创建ServerSocket
ServerSocket serverSocket = new ServierSocket(8888); |
第二步:和客户端建立连接
通过accept方法
Socket accept() 侦听并接受到此套接字的连接。 |
该方法会侦听是否有客户端连接,如果有建立连接,并获取客户端的Socket
也就是说服务端创建之后可以获取客户端连接, 返回一个Socket对象, 这个Socket就是和客户端连接的Socket
Socket socket = serverSocket.accept(); |
第三步: 接受客户端的数据,获取客户端的数据
服务端获取这个socket的输入输出流, 就可以和客户端发送接收数据了socket.getInputStream(); socket.getOutputStream(); |
第五步:获取客户端的ip地址和端口号
使用服务端获取的Socket 获取ip地址和端口.
InetAddress getInetAddress() 返回套接字连接的地址。 |
int getPort() 返回此套接字连接到的远程端口。 |
第四步:关闭客户端和服务端
在服务端中分别调用close方法. |
1.1.3. 案例一:
客户端向服务端发送数据,服务端获取并进信息打印在控制台.
public class TcpServer { public static void main(String[] args) throws IOException { System.out.println("服务端启动:"); // 服务端,监听端口 ServerSocket server = new ServerSocket(50000); // 使用acept进入侦听状态,获取客户端数据 Socket socket = server.accept(); // 获取输入流输出流 InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); // 获取客户端ip,端口 InetAddress inetAddress = socket.getInetAddress(); String ip = inetAddress.getHostAddress(); int port = socket.getPort(); // 获取客户端数据 byte[] byt = new byte[1024]; System.out.println("服务端接受数据:"); int len = in.read(byt); String mess = new String(byt, 0, len); System.out.println("该客户端:" + ip + ":" + port + "发送了:" + mess); // 关闭客户端 socket.close(); // 关闭服务端 server.close(); } } |
1.1.4. 案例二
客户端和服务端实现交互
客户端给服务端发送信息,并接收服务端的回馈信息。
例如:
首先客户端向服务器通话
客户端:你好吗?服务器 |
服务器接到信息
服务器:收到客户端消息 客户端说:你好吗?服务器 |
服务器回馈信息
服务器:收到客户端消息 客户端说:你好吗? 服务器说:我很好 |
客户端接到服务器的信息
客户端:你好吗?服务器 客户端: 收到服务器消息 服务器说: 我很好 |
客户端:
public class TcpClient { public static void main(String[] args) throws IOException, IOException { System.out.println("客户端启动..."); // 创建客户端 Socket socket = new Socket("127.0.0.1", 50000); // 与服务端建立连接,获取输入输出流 InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); BufferedReader br = new BufferedReader(new InputStreamReader( System.in)); byte[] byt = new byte[1024]; while (true) { // 将数据写出到服务端 System.out.println("客户端发送数据..."); System.out.println("你说:"); String mess = br.readLine(); System.out.println("你告诉了服务端:"); out.write(mess.getBytes()); // 获取服务端的回话 int len = in.read(byt); System.out.print("服务端告诉我了:"); System.out.println(new String(byt, 0, len)); if ("bye".equals(mess)) { break; } } // 关闭socket out.close(); } } |
服务端:
public class TcpServer { public static void main(String[] args) throws IOException { System.out.println("服务端启动:"); // 服务端,监听端口 ServerSocket server = new ServerSocket(50000); // 使用acept进入侦听状态,获取客户端数据 Socket socket = server.accept(); // 获取输入流输出流 InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); // 获取客户端ip,端口 InetAddress inetAddress = socket.getInetAddress(); String ip = inetAddress.getHostAddress(); int port = socket.getPort(); byte[] byt = new byte[1024]; BufferedReader br = new BufferedReader(new InputStreamReader( System.in)); while (true) { // 获取客户端数据 System.out.println("服务端接收数据:"); int len = in.read(byt); String mess = new String(byt, 0, len); System.out.println("客户端:" + ip + ":" + port + "告诉了服务端:" + mess); // 向客户端回话. System.out.println("你要告诉客户端:"); String str = br.readLine(); out.write(str.getBytes()); if ("bye".equals(mess)) { break; } } // 关闭客户端 socket.close(); // 关闭服务端 server.close(); } } |
1.1.5. 案例三:
服务器可以客户端的连接.客户端通过键盘录入数据,发送到服务端,服务端接收到数据后,转换成大写在返回给客户端。
需求:
服务器可以客户端的连接.客户端通过键盘录入数据,发送到服务端,服务端接收到数据后,转换成大写在返回给客户端。
客户端:
public class Cilent { public static void main(String[] args) throws UnknownHostException, IOException { System.out.println("客户端启动..."); Socket socket = new Socket("127.0.0.1", 50000); InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.println("请录入:"); String mess = br.readLine(); out.write(mess.getBytes()); System.out.println("-----------获取服务器的回馈--------------"); byte[] byt = new byte[1024]; int len = in.read(byt); System.out.println(new String(byt, 0, len)); socket.close(); } } |
服务端:
public class Cilent { public static void main(String[] args) throws UnknownHostException, IOException { System.out.println("客户端启动..."); Socket socket = new Socket("127.0.0.1", 50000); InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.println("请录入:"); String mess = br.readLine(); out.write(mess.getBytes()); System.out.println("-----------获取服务器的回馈--------------"); byte[] byt = new byte[1024]; int len = in.read(byt); System.out.println(new String(byt, 0, len)); socket.close(); } } |
1.1.6. 多线程服务器
服务器一般是为多个客户端同时服务的, 当每个客户端连接到服务器时, 可以开一条单独的线程处理这个连接.
服务器端:
public class Server { public static void main(String[] args) throws IOException { System.out.println("服务器启动..."); ServerSocket server = new ServerSocket(50000); while (true) { Socket socket = server.accept(); ServerRunnable serverRunnable = new ServerRunnable(socket); Thread t1 = new Thread(serverRunnable); t1.start(); } } } class ServerRunnable implements Runnable { Socket socket; ServerRunnable(Socket socket) { this.socket = socket; } @Override public void run() { try { InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); byte[] byt = new byte[1024]; int len = in.read(byt); String str = new String(byt, 0, len); System.out.println(str); System.out.println("------------服务器转大写--------------"); String upperCase = str.toUpperCase(); System.out.println(upperCase); // 转大写,写回给客户端 out.write(upperCase.getBytes()); } catch (IOException e) { e.printStackTrace(); } finally { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } |
1.1.7. 上传文件
分析:
先启动服务器,再启动客户端.客户端和服务端需要建立连接,服务端向客户端反馈信息.告知客户端”连接成功,请上传文件路径:
客户端:
一: 客户端需要检测文件是否存在,是否是文件.
二: 客户端将文件名,和文件的长度发给服务器,服务器以此判断文件是否存在,文件大小用以验证文件是否上传完毕.
三: 客户端根据服务器端的反馈信息,如果服务器存在该文件,上传结束,不存在开始上传.
四: 客户端开始上传, 使用字节输入流,将文件加载到输入流中,读取输入流,通过socket的输出流写到服务器.
五: 服务器:
根据客户传送的信息,判断文件是否存在如果存在不再上传,需要将结果反馈给客户端.
如果不存在,新建字节输出流,将客户端传送的数据,写到服务器中.判断服务器文件的长度和客户端文件的长度是否一致.一致上传完毕.
客户端:
public class Client { public static void main(String[] args) throws IOException { System.out.println("客户端启动"); Socket socket = new Socket("127.0.0.1", 5000); InputStream ips = socket.getInputStream(); OutputStream ops = socket.getOutputStream(); // 1 ops.write("客户端请求上传文件".getBytes()); // 4 byte[] byt = new byte[1024]; int len = 0; len = ips.read(byt); String mess = new String(byt, 0, len); System.out.println(mess); // 获取上传文件 File file = getFile(); // 获取上传文件名 mess = file.getName(); System.out.println("文件名:" + mess); // 5 ops.write(mess.getBytes()); // 7上传文件大小 ops.write(String.valueOf(file.length()).getBytes()); // 10 len = ips.read(byt); mess = new String(byt, 0, len); if ("文件存在".equals(mess)) { System.out.println("文件存在,无需上传"); return; } // 11 上传 FileInputStream fis = new FileInputStream(file); while ((len = fis.read(byt)) != -1) { ops.write(byt, 0, len); } System.out.println("文件上传完毕"); len = ips.read(byt); System.out.println("服务器说:" + new String(byt, 0, len)); ops.close(); socket.close(); } private static File getFile() { // 用户输入文件路径 Scanner sc = new Scanner(System.in); while (true) { System.out.println("请输入文件的路径名:"); String nextLine = sc.nextLine(); // 创建File File file = new File(nextLine); if (!file.exists()) { System.out.println("文件不存在"); continue; } if (file.isDirectory()) { System.out.println("不支持目录"); continue; } return file; } } } } } |
服务端:
public class Server { public static void main(String[] args) throws IOException { System.out.println("服务端启动"); ServerSocket server = new ServerSocket(5000); Socket client = server.accept(); InputStream ips = client.getInputStream(); OutputStream ops = client.getOutputStream(); // 2 byte[] byt = new byte[1024]; int len = -1; len = ips.read(byt); System.out.println(new String(byt, 0, len)); // 3 ops.write("接收请求,请上传".getBytes()); // 5 len = ips.read(byt); String fileName = new String(byt, 0, len); System.out.println("文件名:" + fileName); // 根据文件名创建File对象, File file = new File("d:\\", fileName); // 8获取文件长度 len = ips.read(byt); long length = Long.parseLong(new String(byt, 0, len)); // 9判断文件是否存在 if (file.exists() && file.length() == length) { System.out.println("文件已经存在"); ops.write("文件存在".getBytes()); return; } else { ops.write("文件不存在".getBytes()); } // 12接收 FileOutputStream fos = new FileOutputStream(file); while ((len = ips.read(byt)) != -1) { fos.write(byt, 0, len); fos.flush(); if (file.length() == length) { System.out.println("文件上传完毕..."); ops.write("文件接收完毕".getBytes()); break; } } fos.close(); client.close(); server.close(); } } |
注意: 服务器中的写出文件时,如果客户端socket没有关闭,那么读不到文件末尾,需要强制结束(判断文件长度是否一致)
相关推荐
- Linux高性能服务器设计
-
C10K和C10M计算机领域的很多技术都是需求推动的,上世纪90年代,由于互联网的飞速发展,网络服务器无法支撑快速增长的用户规模。1999年,DanKegel提出了著名的C10问题:一台服务器上同时...
- 独立游戏开发者常犯的十大错误
-
...
- 学C了一头雾水该咋办?
-
学C了一头雾水该怎么办?最简单的方法就是你再学一遍呗。俗话说熟能生巧,铁杵也能磨成针。但是一味的为学而学,这个好像没什么卵用。为什么学了还是一头雾水,重点就在这,找出为什么会这个样子?1、概念理解不深...
- C++基础语法梳理:inline 内联函数!虚函数可以是内联函数吗?
-
上节我们分析了C++基础语法的const,static以及this指针,那么这节内容我们来看一下inline内联函数吧!inline内联函数...
- C语言实战小游戏:井字棋(三子棋)大战!文内含有源码
-
井字棋是黑白棋的一种。井字棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉、一条龙、三子旗等。将正方形对角线连起来,相对两边依次摆上三个双方棋子,只要将自己的三个棋子走成一条线,对方就算输了。但是,有很多时...
- C++语言到底是不是C语言的超集之一
-
C与C++两个关系亲密的编程语言,它们本质上是两中语言,只是C++语言设计时要求尽可能的兼容C语言特性,因此C语言中99%以上的功能都可以使用C++完成。本文探讨那些存在于C语言中的特性,但是在C++...
- 在C++中,如何避免出现Bug?
-
C++中的主要问题之一是存在大量行为未定义或对程序员来说意外的构造。我们在使用静态分析器检查各种项目时经常会遇到这些问题。但正如我们所知,最佳做法是在编译阶段尽早检测错误。让我们来看看现代C++中的一...
- ESL-通过事件控制FreeSWITCH
-
通过事件提供的最底层控制机制,允许我们有效地利用工具箱,适时选择使用其中的单个工具。FreeSWITCH是一个核心交换与混合矩阵,它周围有几十个模块提供各种功能特性。我们完全控制了所有的即时信息,这些...
- 物理老师教你学C++语言(中篇)
-
一、条件语句与实验判断...
- C语言入门指南
-
当然!以下是关于C语言入门编程的基础介绍和入门建议,希望能帮你顺利起步:C语言入门指南...
- C++选择结构,让程序自动进行决策
-
什么是选择结构?正常的程序都是从上至下顺序执行,这就是顺序结构...
- C++特性使用建议
-
1.引用参数使用引用替代指针且所有不变的引用参数必须加上const。在C语言中,如果函数需要修改变量的值,参数必须为指针,如...
- C++程序员学习Zig指南(中篇)
-
1.复合数据类型结构体与方法的对比C++类:...
- 研一自学C++啃得动吗?
-
研一自学C++啃得动吗?在开始前我有一些资料,是我根据网友给的问题精心整理了一份「C++的资料从专业入门到高级教程」,点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!!个人...
- C++关键字介绍
-
下表列出了C++中的常用关键字,这些关键字不能作为变量名或其他标识符名称。1、autoC++11的auto用于表示变量的自动类型推断。即在声明变量的时候,根据变量初始值的类型自动为此变量选择匹配的...
- 一周热门
-
-
C# 13 和 .NET 9 全知道 :13 使用 ASP.NET Core 构建网站 (1)
-
因果推断Matching方式实现代码 因果推断模型
-
git pull命令使用实例 git pull--rebase
-
git pull 和git fetch 命令分别有什么作用?二者有什么区别?
-
面试官:git pull是哪两个指令的组合?
-
git 执行pull错误如何撤销 git pull fail
-
git fetch 和git pull 的异同 git中fetch和pull的区别
-
git pull 之后本地代码被覆盖 解决方案
-
还可以这样玩?Git基本原理及各种骚操作,涨知识了
-
git命令之pull git.pull
-
- 最近发表
- 标签列表
-
- git pull (33)
- git fetch (35)
- mysql insert (35)
- mysql distinct (37)
- concat_ws (36)
- java continue (36)
- jenkins官网 (37)
- mysql 子查询 (37)
- python元组 (33)
- mysql max (33)
- vba instr (33)
- mybatis 分页 (35)
- vba split (37)
- redis watch (34)
- python list sort (37)
- nvarchar2 (34)
- mysql not null (36)
- hmset (35)
- python telnet (35)
- python readlines() 方法 (36)
- munmap (35)
- docker network create (35)
- redis 集合 (37)
- python sftp (37)
- setpriority (34)