网络编程 p4 TCP编程
TCP编程
-
基本介绍
- 基于客户端——服务端的网络通信;
- 底层使用的是TCP/IP协议;
- 应用场景举例:客户端发送数据,服务端接收并显示在控制台;
- 基于Socket的TCP编程;
-
示意图
-
netstat指令
-
netstat -an
可以查看当前主机网络情况,包括端口监听情况和网络连接情况; -
netstat -an|more
可以分页显示; -
要求在dos控制台下执行 (win+r)
说明:
- Listening 表示某个端口在监听;
- 如果有一个外部程序(客户端)连接到该端口,就会显示一条连接信息;
-
-
注意事项
- 当客户端连接到服务端后,实际上客户端也是通过一个端口和服务端进行通讯的,这端口是TCP/IP来分配的,是随机的;
- 当客户端连接到服务端后,实际上客户端也是通过一个端口和服务端进行通讯的,这端口是TCP/IP来分配的,是随机的;
-
应用案例
-
客户端
package com.hspedu.socket; import java.io.*; import java.net.InetAddress; import java.net.Socket; /** * @author: 86199 * @date: 2023/5/15 15:18 * @description: 字符流 */ public class SocketTCP03Client { public static void main(String[] args) throws IOException { //思路 //1. 连接服务端(ip,端口) //解读:连接本机的 9999 端口,如果连接成功,返回Socket对象 Socket socket = new Socket(InetAddress.getLocalHost(), 9999); System.out.println("客户端 socket返回 = " + socket.getClass()); //2. 连接上后,生成Socket,通过socket.getOutputStream() // 得到和socket对象关联的输出流对象 BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); //3. 通过输出流,写入数据到 数据通道 bufferedWriter.write("hello, server"); bufferedWriter.newLine();//写入一个换行符,表示写入内容结束,要求对方使用readLine的方式来读 bufferedWriter.flush();//如果使用的字符流,需要手动刷新否则数据不会写入数据通道 //4. 通过socket.个体InputStream()读取客户端写入到数据通道的数据,显示 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); String s = bufferedReader.readLine(); System.out.println(s); //5. 关闭流对象和socket,必须关闭 bufferedReader.close(); bufferedWriter.close(); socket.close(); } }
-
服务端
package com.hspedu.socket; import java.io.*; import java.net.ServerSocket; import java.net.Socket; /** * @author: 86199 * @date: 2023/5/15 15:18 * @description: 字符流 */ public class SocketTCP03Server { public static void main(String[] args) throws IOException { //思路 //1. 在本机的9999端口监听,等待连接 // 细节:要求本机没有其他服务在监听9999 // 这个 ServerSocket 可以通过accept() 返回多个Socket[多个客户端连接服务器的并发] ServerSocket serverSocket = new ServerSocket(9999); System.out.println("服务端,在9999端口监听,等待连接..."); //2. 当没有客户端连接9999端口时程序会阻塞,等待连接 // 如果有客户端连接,则会返回Socket对象,程序继续 Socket accept = serverSocket.accept(); System.out.println("服务端 socket = " + accept.getClass()); //3. 通过socket.个体InputStream()读取客户端写入到数据通道的数据,显示 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(accept.getInputStream()));//读不到内容会阻塞 //4. IO读取 String s = bufferedReader.readLine(); System.out.println(s); //5. 通过输出流,写入数据到 数据通道 BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream())); bufferedWriter.write("hello, client"); bufferedWriter.newLine();//写入一个换行符,表示写入内容结束,要求对方使用readLine的方式来读 bufferedWriter.flush();//如果使用的字符流,需要手动刷新否则数据不会写入数据通道 //设置结束标记 //6. 关闭流对象和socket,必须关闭 bufferedWriter.close(); bufferedReader.close(); accept.close(); serverSocket.close(); } }
-
StreamUtils类
package com.hspedu.upload; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.InputStreamReader; /** * @author: 86199 * @date: 2023/5/16 14:57 * @description: 工具类 */ public class StreamUtils { public static byte[] streamToByteArray(InputStream is) throws Exception { // 创建输出流对象 ByteArrayOutputStream bos = new ByteArrayOutputStream(); // 字节数组 byte[] b = new byte[1024]; int len; while ((len = is.read(b)) != -1) { // 循环读取 // 把读取到的数据,写入 bos bos.write(b, 0, len); } byte[] array = bos.toByteArray(); bos.close(); return array; } public static String streamToString(InputStream is) throws Exception { BufferedReader reader = new BufferedReader(new InputStreamReader(is)); StringBuilder builder = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { builder.append(line + "\r\n"); } return builder.toString(); } }
-
服务端
package com.hspedu.upload; import java.io.*; import java.net.ServerSocket; import java.net.Socket; /** * @author: 86199 * @date: 2023/5/15 16:24 * @description: */ public class TCPFileUploadServer { public static void main(String[] args) throws Exception { ServerSocket serverSocket = new ServerSocket(8888); System.out.println("服务端在8888等待连接......"); Socket accept = serverSocket.accept(); String filePath = "D:\\program\\javaProject\\Idea_Java_Project\\chapter21\\src\\copy.jpg"; BufferedInputStream bis = new BufferedInputStream(accept.getInputStream()); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath)); byte[] bytes = StreamUtils.streamToByteArray(bis); bos.write(bytes); bos.close(); //向客户端回复“收到图片” BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream())); bufferedWriter.write("收到图片"); bufferedWriter.flush(); accept.shutdownOutput(); //关闭流和socket bis.close(); accept.close(); serverSocket.close(); } }
-
客户端
package com.hspedu.upload; import java.io.*; import java.net.InetAddress; import java.net.Socket; /** * @author: 86199 * @date: 2023/5/15 16:24 * @description: */ public class TCPFileUploadClient { public static void main(String[] args) throws Exception { Socket socket = new Socket(InetAddress.getLocalHost(), 8888); String filePath = "e:\\qie.jpg"; BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream()); BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath)); byte[] bytes = StreamUtils.streamToByteArray(bis); bos.write(bytes); bos.flush(); //没有手动调用flush方法,也没有调用close方法关闭流,数据复制失败, //因为数据还在内部缓冲区,并没有输出 (因为内部缓冲区没有被放满,不调用flush方法,不会输出) bis.close(); socket.shutdownOutput(); //接收消息 InputStream inputStream = socket.getInputStream(); String s = StreamUtils.streamToString(inputStream); System.out.println(s); //关闭流和socket inputStream.close(); bos.close(); socket.close(); } }
-