【Java】网络编程--Socket与TCP网络通信编程

简介: 文章目录写在前面1 Socket2 TCP网络通信编程2.1 TCP字节流编程2.1.1 案例:客户端发送数据,服务端接收并显示2.1.2 案例进阶:双向通信2.2 TCP字符流编程2.3 网络上传文件

1 Socket

🐰 基本介绍:


套接字(Socket)开发网络应用程序被广泛采用,以至于成为事实上的标准;

通信的两端都要有Socket,是两台机器间通信的端点;

网络通信其实就是Socket间的通信;

Socket允许程序把网络连接当作一个流,数据可以在两个Socket间通过IO传输;

一般主动发起通信的应用程序属于客户端,等待通信请求的为服务端

Socket该如何理解?



2 TCP网络通信编程

2.1 TCP字节流编程

因资源有限,笔者操作均在同一台计算机完成


题目摘自:韩顺平Java_TCP字节流编程1、2


2.1.1 案例:客户端发送数据,服务端接收并显示

编写一个服务器端,和一个客户端。服务端在 9999端口监听,客户端连接到服务端,并发送"hello,server",然后退出。服务端接收到客户端发送的信息后,输出该信息,并退出。


服务端代码:

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 * 服务端
 */
public class SocketTCPServer1 {
    public static void main(String[] args) throws IOException {
        //1.在本机的9999端口监听,等待连接,要求本机没有其他服务在监听9999
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服务端,在9999端口监听,等待连接..");
        //2.当没有客户端连接9999端口时,程序会阻塞,等待连接
        //如果有客户端连接,则会返回Socket对象,程序继续
        Socket socket = serverSocket.accept();
        System.out.println("服务端 socket=" + socket.getClass());
        //3.通过socket.getInputStream() 读取客户端写入数据通道的数据,并显示
        InputStream inputStream = socket.getInputStream();
        //4.IO读取
        byte[] buf = new byte[1024];
        int readLen = 0;
        while ((readLen = inputStream.read(buf)) != -1){
            System.out.println(new String(buf, 0, readLen));
        }
        //5.关闭资源
        inputStream.close();
        socket.close();
        serverSocket.close();
        System.out.println("服务端退出......");
    }
}

客户端代码:

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 * 客户端,发送"hello,server"给服务端
 */
public class SockerTCPClient1 {
    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,通过输出流,写入数据到 数据通道
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("hello,server".getBytes());
        //3.关闭流对象
        outputStream.close();
        socket.close();
        System.out.println("客户端退出......");
    }
}

结果如下


2.1.2 案例进阶:双向通信

1.编写一个服务端,和一个客户端;

2.服务端在9999端口监听;

3.客户端连接到服务端,发送"hello,server",并接收服务端回发的"hello,cilent",再退出;

4.服务器端接收到客户端发送的信息,输出,并发送"hello, cilent",再退出


该案例为案例1的进阶,可以直接在上述代码中进行修改。


服务端代码:


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 * 服务端
 */
public class SocketTCPServer1 {
    public static void main(String[] args) throws IOException {
        //1.在本机的9999端口监听,等待连接,要求本机没有其他服务在监听9999
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服务端,在9999端口监听,等待连接..");
        //2.当没有客户端连接9999端口时,程序会阻塞,等待连接
        //如果有客户端连接,则会返回Socket对象,程序继续
        Socket socket = serverSocket.accept();
        System.out.println("服务端 socket=" + socket.getClass());
        //3.通过socket.getInputStream() 读取客户端写入数据通道的数据,并显示
        InputStream inputStream = socket.getInputStream();
        //4.IO读取
        byte[] buf = new byte[1024];
        int readLen = 0;
        while ((readLen = inputStream.read(buf)) != -1){
            System.out.println(new String(buf, 0, readLen));
        }
        socket.shutdownInput();
        //5.写入数据到数据通道
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("hello, client".getBytes());
        socket.shutdownOutput();
        //6.关闭资源
        inputStream.close();
        outputStream.close();
        socket.close();
        serverSocket.close();
        System.out.println("服务端退出......");
    }
}

客户端代码

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 * 客户端,发送"hello,server"给服务端
 */
public class SockerTCPClient1 {
    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,通过输出流,写入数据到 数据通道
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("hello,server".getBytes());
        socket.shutdownOutput();
        //3.读取服务端数据
        InputStream inputStream = socket.getInputStream();
        byte[] buf = new byte[1024];
        int readLine = 0;
        while ((readLine = inputStream.read(buf)) != -1){
            System.out.println(new String(buf, 0, readLine));
        }
        //4.关闭流对象
        inputStream.close();
        outputStream.close();
        socket.close();
        System.out.println("客户端退出......");
    }
}

注意使用 socket.shutdownOutput() 设置结束标记

类比一下生活中两个人聊天,对方如果不停止讲话,或者告诉你说完了,你始终无法确定对方是否已经说完了话,因此,你会一直处于听的状态(如果礼貌的前提下!)

网络通信也一样,负责监听的服务端,并不知道客户端是否已经说完了话,因此,客户端在发送消息完毕时,应该给服务端发送一个结束标记!只有这样,服务端才知道该何时停止读取(Input)状态,进行下一步操作。


结果:




2.2 TCP字符流编程

需求同案例进阶:双向通信,不同点是,这次我们尝试使用字符流来实现!


服务端代码:

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 * 服务端
 */
public class SocketTCPServer1 {
    public static void main(String[] args) throws IOException {
        //1.在本机的9999端口监听,等待连接,要求本机没有其他服务在监听9999
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服务端,在9999端口监听,等待连接..");
        //2.当没有客户端连接9999端口时,程序会阻塞,等待连接
        //如果有客户端连接,则会返回Socket对象,程序继续
        Socket socket = serverSocket.accept();
        System.out.println("服务端 socket=" + socket.getClass());
        //3.通过socket.getInputStream() 读取客户端写入数据通道的数据,并显示
        InputStream inputStream = socket.getInputStream();
        //4.IO读取,使用字符流
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String s = bufferedReader.readLine();
        System.out.println(s);
        //5.写入数据到数据通道
        OutputStream outputStream = socket.getOutputStream();
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
        bufferedWriter.write("hello,client");
        bufferedWriter.newLine();
        bufferedWriter.flush();
        //6.关闭资源
        bufferedReader.close();
        bufferedWriter.close();
        socket.close();
        serverSocket.close();
        System.out.println("服务端退出......");
    }
}

客户端代码

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 * 客户端,发送"hello,server"给服务端
 */
public class SockerTCPClient1 {
    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,通过输出流,写入数据到 数据通道
        OutputStream outputStream = socket.getOutputStream();
        //字符流需要包装和转化
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
        bufferedWriter.write("hello,server");
        //插入一个换行符表示写入内容结束
        bufferedWriter.newLine();
        //需要刷新
        bufferedWriter.flush();
        //3.读取服务端数据
        InputStream inputStream = socket.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String s = bufferedReader.readLine();
        System.out.println(s);
        //4.关闭流对象
        bufferedReader.close();
        bufferedWriter.close();
        socket.close();
        System.out.println("客户端退出......");
    }
}

2.3 网络上传文件

需求如下:将客户端的图片,通过网络上传到服务器,服务器回复消息


1.编写一个服务端,一个客户端;

2.服务端在8888端口监听;

3.客户端连接到服务端,发送一张图片;

4.服务端接收到图片后将客户端发送的图片保存到src目录,并发送“收到图片”后退出;

5.客户端在接收到服务端“收到图片”后退出;

6.要求使用StreamUtils,java(自己封装的)


🐱 思路分析:


先将磁盘上的文件读入客户端,存储在字节数组中(图片是二进制);

将字节数组(文件数据)通过Socket获取的输出流输出到数据通道上;

在服务端,需要通过Socket获取输入流存储到字节数组中;

然后,在通过输出流将字节数组的数据保存到磁盘上;

通过Socket获得输出流,将“收到图片”打入数据通道,结束;

客户端通过输入流,读取数据,接收到“收到图片”提示,显示信息,结束。

StreamUtils.java

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 */
public class StreamUtils {
    /**
     * 将输入流转化成 byte[],即可以将文件读入到字节数组
     * @param is
     * @return
     * @throws Exception
     */
    public static byte[] streamToByteArray(InputStream is) throws Exception{
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        byte[] bytes = new byte[1024];
        int len = 0;
        while ((len=is.read(bytes))!=-1){
            bos.write(bytes, 0, len);
        }
        byte[] array = bos.toByteArray();
        bos.close();
        return array;
    }
}

服务端

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 * 服务端
 */
public class TCPFileUploadServer {
    public static void main(String[] args) throws Exception {
        //1.服务端在本机8888端口监听
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务端在8888端口监听");
        //2.等待连接
        Socket socket = serverSocket.accept();
        //3.读取客户端的数据
        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        byte[] bytes = StreamUtils.streamToByteArray(bis);
        //4.将数组写入到指定路径
        String filePath = "D:\\Ideaproject2021\\JavaSE\\src\\upload\\zzf2.jpg";
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
        bos.write(bytes);
        bos.close();
        //5.向客户端发送,收到图片
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        writer.write("收到图片");
        writer.newLine();
        writer.flush();
        socket.shutdownOutput();
        //关闭其他资源
        writer.close();
        bis.close();
        socket.close();
        serverSocket.close();
    }
}

客户端

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
/**
 * @author 兴趣使然黄小黄
 * @version 1.0
 * 客户端
 */
public class TCPFileUploadClient {
    public static void main(String[] args) throws Exception {
        //1.客户端连接服务端,得到socket对象
        Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
        //2.创建读取磁盘文件的输入流
        String filePath = "C:\\Users\\26510\\Desktop\\csdn\\zzf.jpg";
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
        //3.把文件写入到字节数组中
        byte[] bytes = StreamUtils.streamToByteArray(bis);
        //4.将字节数组的数据发送到服务端
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
        bos.write(bytes);
        bis.close();
        socket.shutdownOutput();
        //5.获取信息
        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String s = reader.readLine();
        System.out.println(s);
        //关闭流
        reader.close();
        bos.close();
        socket.close();
    }
}

运行后,图片成功上传到服务端

相关文章
|
7月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
400 1
|
7月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
375 1
|
7月前
|
机器学习/深度学习 分布式计算 Java
Java与图神经网络:构建企业级知识图谱与智能推理系统
图神经网络(GNN)作为处理非欧几里得数据的前沿技术,正成为企业知识管理和智能推理的核心引擎。本文深入探讨如何在Java生态中构建基于GNN的知识图谱系统,涵盖从图数据建模、GNN模型集成、分布式图计算到实时推理的全流程。通过具体的代码实现和架构设计,展示如何将先进的图神经网络技术融入传统Java企业应用,为构建下一代智能决策系统提供完整解决方案。
650 0
|
SQL 监控 安全
网络安全与信息安全:漏洞、加密与安全意识
随着互联网的迅猛发展,网络安全和信息安全问题日益受到关注。本文深入探讨了网络安全漏洞、加密技术以及提高个人和组织的安全意识的重要性。通过分析常见的网络攻击手段如缓冲区溢出、SQL注入等,揭示了计算机系统中存在的缺陷及其潜在威胁。同时,详细介绍了对称加密和非对称加密算法的原理及应用场景,强调了数字签名和数字证书在验证信息完整性中的关键作用。此外,还讨论了培养良好上网习惯、定期备份数据等提升安全意识的方法,旨在帮助读者更好地理解和应对复杂的网络安全挑战。
|
SQL 安全 网络安全
网络安全与信息安全:知识分享####
【10月更文挑战第21天】 随着数字化时代的快速发展,网络安全和信息安全已成为个人和企业不可忽视的关键问题。本文将探讨网络安全漏洞、加密技术以及安全意识的重要性,并提供一些实用的建议,帮助读者提高自身的网络安全防护能力。 ####
465 17
|
SQL 安全 网络安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
随着互联网的普及,网络安全问题日益突出。本文将从网络安全漏洞、加密技术和安全意识三个方面进行探讨,旨在提高读者对网络安全的认识和防范能力。通过分析常见的网络安全漏洞,介绍加密技术的基本原理和应用,以及强调安全意识的重要性,帮助读者更好地保护自己的网络信息安全。
357 10
|
存储 SQL 安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
随着互联网的普及,网络安全问题日益突出。本文将介绍网络安全的重要性,分析常见的网络安全漏洞及其危害,探讨加密技术在保障网络安全中的作用,并强调提高安全意识的必要性。通过本文的学习,读者将了解网络安全的基本概念和应对策略,提升个人和组织的网络安全防护能力。
|
SQL 安全 网络安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
在数字化时代,网络安全和信息安全已成为我们生活中不可或缺的一部分。本文将介绍网络安全漏洞、加密技术和安全意识等方面的内容,并提供一些实用的代码示例。通过阅读本文,您将了解到如何保护自己的网络安全,以及如何提高自己的信息安全意识。
350 10
|
监控 安全 网络安全
网络安全与信息安全:漏洞、加密与意识的交织
在数字时代的浪潮中,网络安全与信息安全成为维护数据完整性、保密性和可用性的关键。本文深入探讨了网络安全中的漏洞概念、加密技术的应用以及提升安全意识的重要性。通过实际案例分析,揭示了网络攻击的常见模式和防御策略,强调了教育和技术并重的安全理念。旨在为读者提供一套全面的网络安全知识框架,从而在日益复杂的网络环境中保护个人和组织的资产安全。
|
存储 监控 安全
云计算与网络安全:云服务、网络安全、信息安全等技术领域的融合与挑战
本文将探讨云计算与网络安全之间的关系,以及它们在云服务、网络安全和信息安全等技术领域中的融合与挑战。我们将分析云计算的优势和风险,以及如何通过网络安全措施来保护数据和应用程序。我们还将讨论如何确保云服务的可用性和可靠性,以及如何处理网络攻击和数据泄露等问题。最后,我们将提供一些关于如何在云计算环境中实现网络安全的建议和最佳实践。

热门文章

最新文章