Java网络编程 ---- TCP 网络通信编程(二)

简介: Java网络编程 ---- TCP 网络通信编程(二)

6. 应用案例 4 文件上传

  1. 编写一个服务端,和一个客户端
  2. 服务器端在8888端口监听
  3. 客户端连接到服务端,发送一张图片 e:\bg.jpg

  4. 服务器端接收到客户端发送的图片,保存到src下,发送"收到图片”再退出
  5. 客户端接收到服务端发送的“收到图片”,再退出
  6. 该程序要求使用StreamUtils.java,我们直接使用
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
 * 此类用于演示关于流的读写方法
 *
 */
public class StreamUtils {
  /**
   * 功能:将输入流转换成byte[], 即可以把文件的内容读入到byte[]
   * @param is
   * @return
   * @throws Exception
   */
  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.write(b, 0, len);//把读取到的数据,写入bos  
    }
    byte[] array = bos.toByteArray();//然后将bos 转成字节数组
    bos.close();
    return array;
  }
  /**
   * 功能:将InputStream转换成String
   * @param is
   * @return
   * @throws Exception
   */
  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();
  }
}

TCPFileUploadServer.java

TCPFileUploadClient.java

6.1 创建服务器

package java学习.网络编程.TCP;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPFileUploadServer {
    public static void main(String[] args) throws IOException {
//        服务器在8888端口监听
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务器在8888端口监听");
//        等待连接
        Socket socket = serverSocket.accept();
        System.out.println( "服务端 socket=" + socket.getClass() );
    }
}

6.2 客户端读取文件上传文件

package java学习.网络编程.TCP;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class TCPFileUploadClient {
    public static void main(String[] args) throws Exception {
//        连接服务端的8888端口
        Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
//        文件的路径
        String filePath = "e:\\bg.jpg";
//        输入流,读取图片
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
//        调用StreamUtils.streamToByteArray读取图片,获取二进制数组
        byte[] bytes = StreamUtils.streamToByteArray(bis);
//        通过 socket 获取到输出流, 将 bytes 数据发送给服务端
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
        bos.write(bytes);//将文件对应的字节数组的内容,写入到数据通道
        socket.shutdownOutput();//设置写入数据的结束标记
//        关闭流
        bos.close();
        bis.close();
        socket.close();
    }
}

6.3 服务端读取流中的文件存放在src下

package java学习.网络编程.TCP;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPFileUploadServer {
    public static void main(String[] args) throws Exception {
//        服务器在8888端口监听
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务器在8888端口监听");
//        等待连接
        Socket socket = serverSocket.accept();
        System.out.println( "服务端 socket=" + socket.getClass() );
//        输入流,读取流中数据
        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
//        调用StreamUtils.streamToByteArray将输入流中的数据读到数组中
        byte[] bytes = StreamUtils.streamToByteArray(bis);
//        将得到 bytes 数组,写入到指定的路径,就得到一个文件了
//        路径
        String filePath = "src\\bg.jpg";
//        输出流
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
        bos.write(bytes);
//        关闭
        bos.close();
        bis.close();
        socket.close();
        serverSocket.close();
    }
}

6.4 服务端回复信息

package java学习.网络编程.TCP;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPFileUploadServer {
    public static void main(String[] args) throws Exception {
//        服务器在8888端口监听
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务器在8888端口监听");
//        等待连接
        Socket socket = serverSocket.accept();
        System.out.println( "服务端 socket=" + socket.getClass() );
//        输入流,读取流中数据
        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
//        调用StreamUtils.streamToByteArray将输入流中的数据读到数组中
        byte[] bytes = StreamUtils.streamToByteArray(bis);
//        将得到 bytes 数组,写入到指定的路径,就得到一个文件了
//        路径
        String filePath = "src\\bg.jpg";
//        输出流
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
        bos.write(bytes);
//        回复信息
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        bw.write("收到图片");
        bw.flush();//把内容刷新到数据通道
//        客户端以字节流读取信息,可以设置如下结束标记
        socket.shutdownOutput();//设置写入结束标记
//        关闭
        bw.close();
        bos.close();
        bis.close();
        socket.close();
        serverSocket.close();
    }
}

6.5 服务端接收回复信息

package java学习.网络编程.TCP;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class TCPFileUploadClient {
    public static void main(String[] args) throws Exception {
//        连接服务端的8888端口
        Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
//        文件的路径
        String filePath = "e:\\bg.jpg";
//        输入流,读取图片
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
//        调用StreamUtils.streamToByteArray读取图片,获取二进制数组
        byte[] bytes = StreamUtils.streamToByteArray(bis);
//        通过 socket 获取到输出流, 将 bytes 数据发送给服务端
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
        bos.write(bytes);//将文件对应的字节数组的内容,写入到数据通道
        socket.shutdownOutput();//设置写入数据的结束标记
//        接收服务端回复的信息
        InputStream inputStream = socket.getInputStream();
//        使用 StreamUtils 的方法,直接将 inputStream 读取到的内容 转成字符串
        String s = StreamUtils.streamToString(inputStream);
        System.out.println(s);
//        关闭流
        inputStream.close();
        bos.close();
        bis.close();
        socket.close();
    }
}

效果

7. netstat 指令

  1. netstat -an 可以查看当前主机网络情况,包括端口监听情况和网络连接情况
  2. netstat -an | more可以分页显示 空格下一页
  3. 要求在dos控制台下执行 win+r

说明:

(1) Listening表示某个端口在监听

(2)如果有一个外部程序(客户端)连接到该端口,就会显示一条连接信息.

(3)可以输入ctrl +c退出指令

netstat -a
netstat -an | more

netstat -an

可以查看哪些应用在监听端口(要用管理员的身份打开命令窗口)

8. TCP 网络通讯不为人知的秘密

当客户端连接到服务端后,实际上客户端也是通过一个端口和服务端进行通讯的,这个端口是TCP/IP来分配的,是不确定的,是随机的.



相关文章
|
21天前
|
存储 缓存 Java
Java 并发编程——volatile 关键字解析
本文介绍了Java线程中的`volatile`关键字及其与`synchronized`锁的区别。`volatile`保证了变量的可见性和一定的有序性,但不能保证原子性。它通过内存屏障实现,避免指令重排序,确保线程间数据一致。相比`synchronized`,`volatile`性能更优,适用于简单状态标记和某些特定场景,如单例模式中的双重检查锁定。文中还解释了Java内存模型的基本概念,包括主内存、工作内存及并发编程中的原子性、可见性和有序性。
Java 并发编程——volatile 关键字解析
|
25天前
|
负载均衡 网络协议 算法
不为人知的网络编程(十九):能Ping通,TCP就一定能连接和通信吗?
这网络层就像搭积木一样,上层协议都是基于下层协议搭出来的。不管是ping(用了ICMP协议)还是tcp本质上都是基于网络层IP协议的数据包,而到了物理层,都是二进制01串,都走网卡发出去了。 如果网络环境没发生变化,目的地又一样,那按道理说他们走的网络路径应该是一样的,什么情况下会不同呢? 我们就从路由这个话题聊起吧。
56 4
不为人知的网络编程(十九):能Ping通,TCP就一定能连接和通信吗?
|
25天前
|
算法 Java 调度
java并发编程中Monitor里的waitSet和EntryList都是做什么的
在Java并发编程中,Monitor内部包含两个重要队列:等待集(Wait Set)和入口列表(Entry List)。Wait Set用于线程的条件等待和协作,线程调用`wait()`后进入此集合,通过`notify()`或`notifyAll()`唤醒。Entry List则管理锁的竞争,未能获取锁的线程在此排队,等待锁释放后重新竞争。理解两者区别有助于设计高效的多线程程序。 - **Wait Set**:线程调用`wait()`后进入,等待条件满足被唤醒,需重新竞争锁。 - **Entry List**:多个线程竞争锁时,未获锁的线程在此排队,等待锁释放后获取锁继续执行。
61 12
|
21天前
|
网络协议
TCP报文格式全解析:网络小白变高手的必读指南
本文深入解析TCP报文格式,涵盖源端口、目的端口、序号、确认序号、首部长度、标志字段、窗口大小、检验和、紧急指针及选项字段。每个字段的作用和意义详尽说明,帮助理解TCP协议如何确保可靠的数据传输,是互联网通信的基石。通过学习这些内容,读者可以更好地掌握TCP的工作原理及其在网络中的应用。
|
21天前
|
存储 安全 Java
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
117 2
|
1月前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
6月前
|
安全 Java Linux
(七)Java网络编程-IO模型篇之从BIO、NIO、AIO到内核select、epoll剖析!
IO(Input/Output)方面的基本知识,相信大家都不陌生,毕竟这也是在学习编程基础时就已经接触过的内容,但最初的IO教学大多数是停留在最基本的BIO,而并未对于NIO、AIO、多路复用等的高级内容进行详细讲述,但这些却是大部分高性能技术的底层核心,因此本文则准备围绕着IO知识进行展开。
203 1
|
6月前
|
Java 大数据
如何在Java中进行网络编程:Socket与NIO
如何在Java中进行网络编程:Socket与NIO
|
8月前
|
监控 Java 开发者
深入理解 Java 网络编程和 NIO
【4月更文挑战第19天】Java网络编程基于Socket,但NIO(非阻塞I/O)提升了效率和性能。NIO特点是非阻塞模式、选择器机制和缓冲区,适合高并发场景。使用NIO涉及通道、选择器和事件处理,优点是高并发、资源利用率和可扩展性,但复杂度、错误处理和性能调优是挑战。开发者应根据需求选择是否使用NIO,并深入理解其原理。
84 1
|
JSON 前端开发 安全
Java网络编程IO模型 --- BIO、NIO、AIO详解
Java网络编程IO模型 --- BIO、NIO、AIO详解
364 0
Java网络编程IO模型 --- BIO、NIO、AIO详解