2024年Java 网络编程_java实现计算机网络,java面试问项目

总结

如果你选择了IT行业并坚定的走下去,这个方向肯定是没有一丝问题的,这是个高薪行业,但是高薪是凭自己的努力学习获取来的,这次我把P8大佬用过的一些学习笔记(pdf)都整理在本文中了

《Java中高级核心知识全面解析》

小米商场项目实战,别再担心面试没有实战项目:

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

网络编程也叫做Socket编程,即套接字编程。套接字指的是两台设备之间通讯的端点。

在这里插入图片描述

(一)TCP网络编程

1.概述

TCP通信能实现两台计算机之间的数据交互,通信的两端,要严格区分为客户端(Client)与服务端(Server)。

(1)两端通信时步骤:
  1. 服务端程序,需要事先启动,等待客户端的连接。
  2. 客户端主动连接服务器端,连接成功才能通信。服务端不可以主动连接客户端。
(2)在Java中,提供了两个类用于实现TCP通信程序:
  1. 客户端:java.net.Socket 类表示。创建Socket对象,向服务端发出连接请求,服务端响应请求,两者建立连接开始通信。
  2. 服务端:java.net.ServerSocket 类表示。创建ServerSocket对象,相当于开启一个服务,并等待客户端的连接。
2.Socket类

Socket 类:该类实现客户端套接字,套接字指的是两台设备之间通讯的端点。

(1)构造方法摘要
  • public Socket(String host, int port) :创建套接字对象并将其连接到指定主机上的指定端口号。如果指定的host是null ,则相当于指定地址为回送地址
    回送地址(127.x.x.x) 是本机回送地址(Loopback Address),主要用于网络软件测试以及本地机进程间通信,无论什么程序,一旦使用回送地址发送数据,立即返回,不进行任何网络传输。

案例演示

Socket client = new Socket("127.0.0.1", 6666);

(2)常用方法摘要
  • public InputStream getInputStream() : 返回此套接字的输入流。

    • 如果此Scoket具有相关联的通道,则生成的InputStream 的所有操作也关联该通道。
    • 关闭生成的InputStream也将关闭相关的Socket。
  • public OutputStream getOutputStream() : 返回此套接字的输出流。

    • 如果此Socket具有相关联的通道,则生成的OutputStream 的所有操作也关联该通道。
    • 关闭生成的OutputStream也将关闭相关的Socket。
  • public void close() :关闭此套接字。

    • 一旦一个socket被关闭,它不可再使用。
    • 关闭此socket也将关闭相关的InputStream和OutputStream 。
  • public void shutdownOutput() : 禁用此套接字的输出流。

    • 任何先前写出的数据将被发送,随后终止输出流。
3.ServerSocket类

ServerSocket类:这个类实现了服务器套接字,该对象等待通过网络的请求。

(1)构造方法摘要
  • public ServerSocket(int port) :使用该构造方法在创建ServerSocket对象时,就可以将其绑定到一个指定的端口号上,参数port就是端口号。

案例演示

ServerSocket server = new ServerSocket(6666);

(2)常用方法摘要
  • public Socket accept() :侦听并接受连接,返回一个新的Socket对象,用于和客户端实现通信。该方法会一直阻塞直到建立连接。
4.代码实现

案例演示1

客户端:

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

public class TCPClient {
    public static void main(String[] args){
        Socket socket = null;
        OutputStream os = null;
        try {
            //1、创建Socket对象,它的第一个参数需要的是服务端的IP,第二个参数是服务端的端口
            InetAddress inet = InetAddress.getByName("127.0.0.1");
            socket = new Socket(inet,8090);
            //2、获取一个输出流,用于写出要发送的数据
            os = socket.getOutputStream();
            //3、写出数据
            os.write("你好,我是客户端!".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {//4、释放资源
            if(socket!=null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(os!=null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

服务端:

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

public class TCPServer {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        InputStream is = null;
        ByteArrayOutputStream baos = null;
        try {
            //1、创建服务端的ServerSocket,指明自己的端口号
            serverSocket = new ServerSocket(8090);
            //2、调用accept接收到来自于客户端的socket
            socket = serverSocket.accept();//阻塞式监听,会一直等待客户端的接入
            //3、获取socket的输入流
            is = socket.getInputStream();

// 不建议这样写:因为如果我们发送的数据有汉字,用String的方式输出可能会截取汉字,产生乱码
// int len=0;
// byte[] buffer = new byte[1024];
// while ((len=is.read(buffer))!=-1){
// String str = new String(buffer, 0, len);
// System.out.println(str);
// }
            
            //4、读取输入流中的数据
            //ByteArrayOutputStream的好处是它可以根据数据的大小自动扩充
            baos = new ByteArrayOutputStream();
            int len=0;
            byte[] buffer = new byte[1024];
            while ((len=is.read(buffer))!=-1){
                baos.write(buffer,0,len);
            }
            System.out.println("收到了来自于客户端"+socket.getInetAddress().getHostName()
                    +"的消息:"+baos.toString());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {//5、关闭资源
            if(serverSocket!=null){
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(socket!=null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(is!=null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(baos!=null){
                try {
                    baos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}


在这里插入图片描述
服务器是没有IO流的,服务器可以获取到请求的客户端对象socket
使用每个客户端socket中提供的IO流和客户端进行交互
服务器使用客户端的字节输入流读取客户端发送的数据
服务器使用客户端的字节输出流给客户端回写数据

案例演示2
服务端向客户端回写数据

客户端:

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

public class TCPClient {
    public static void main(String[] args){
        Socket socket = null;
        OutputStream os = null;
        ByteArrayOutputStream baos=null;
        InputStream is=null;
        try {
            //1、创建Socket对象,它的第一个参数需要的是服务端的IP,第二个参数是服务端的端口
            InetAddress inet = InetAddress.getByName("127.0.0.1");
            socket = new Socket(inet,8888);
            //2、获取一个输出流,用于写出要发送的数据
            os = socket.getOutputStream();
            //3、写出数据
            os.write("你好,我是客户端!".getBytes());
            //==========================解析回复==================================
            //4、首先必须通知服务器,我已经输出完毕了,不然服务端不知道什么时候输出完毕
            //服务端的while循环会一直执行,会阻塞
            socket.shutdownOutput();
            ///5、获取输入流,用于读取服务端回复的数据
            is = socket.getInputStream();
            baos = new ByteArrayOutputStream();
            int len=0;
            byte[] buffer = new byte[1024];
            while ((len=is.read(buffer))!=-1){
                baos.write(buffer,0,len);
            }
            System.out.println("收到了来自服务端的消息:"+baos.toString());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {//6、释放资源
            if(socket!=null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(os!=null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(is!=null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (baos!=null){
                try {
                    baos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

服务端:

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

public class TCPServer {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        InputStream is = null;
        ByteArrayOutputStream baos = null;
        OutputStream os=null;
        try {
            //1、创建服务端的ServerSocket,指明自己的端口号
            serverSocket = new ServerSocket(8888);
            //2、调用accept接收到来自于客户端的socket
            socket = serverSocket.accept();//阻塞式监听,会一直等待客户端接入
            //3、获取socket的输入流
            is = socket.getInputStream();

// 不建议这样写:因为如果我们发送的数据有汉字,用String的方式输出可能会截取汉字,产生乱码
// int len=0;
// byte[] buffer = new byte[1024];
// while ((len=is.read(buffer))!=-1){
// String str = new String(buffer, 0, len);
// System.out.println(str);
// }

            //4、读取输入流中的数据
            //ByteArrayOutputStream的好处是它可以根据数据的大小自动扩充
            baos = new ByteArrayOutputStream();
            int len=0;
            byte[] buffer = new byte[1024];
            while ((len=is.read(buffer))!=-1){
                baos.write(buffer,0,len);
            }
            System.out.println("收到了来自于客户端"+socket.getInetAddress().getHostName()
                    +"的消息:"+baos.toString());
            //===========================回复==========================================
            //5、获取一个输出流,写出回复给客户端
            os = socket.getOutputStream();
            //6、写出数据
            os.write("你好,我是服务端".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {//7、关闭资源
            if(serverSocket!=null){
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(socket!=null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(is!=null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(baos!=null){
                try {
                    baos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(os!=null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

在这里插入图片描述
在这里插入图片描述
案例演示3
上传文件:客户端发送文件给服务端,服务端将文件保存在本地
在这里插入图片描述

客户端:

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

public class TCPClient {
    public static void main(String[] args) {
        Socket socket = null;
        FileInputStream fis = null;
        OutputStream os = null;
        try {
            //1、创建Socket对象,它的第一个参数需要的是服务端的IP,第二个参数是服务端的端口
            InetAddress inet = InetAddress.getByName("127.0.0.1");
            socket = new Socket(inet, 8888);
            //2、创建一个文件输入流,读取要上传的文件
            fis = new FileInputStream("D:/test/touxiang.jpg");
            //3、获取一个输出流,用于写出要发送的数据
            os = socket.getOutputStream();
            byte[] buffer = new byte[1024];
            int len=0;
            while((len=fis.read(buffer))!=-1){
                //4、写出数据
                os.write(buffer,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {//5、释放资源
            if(socket!=null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fis!=null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(os!=null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

服务端:

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

public class TCPServer {
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        FileOutputStream fos = null;
        InputStream is = null;
        try {
            //1、创建服务端的ServerSocket,指明自己的端口号
            serverSocket = new ServerSocket(8888);
            //2、调用accept接收到来自于客户端的socket
            socket = serverSocket.accept();//阻塞式监听,会一直等待客户端的接入
            //3、创建一个文件输出流,用于将读取到的客户端上传的文件输出
            fos = new FileOutputStream("touxiang.jpg");
            //4、获取socket的输入流
            is = socket.getInputStream();
            byte[] buffer = new byte[1024];
            int len=0;
            while((len=is.read(buffer))!=-1){
                fos.write(buffer,0,len);//5、写出文件
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {//6、释放资源
            if(serverSocket!=null){
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(socket!=null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fos!=null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(is!=null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

假设大海里有许多岛屿,客户端和服务端相当于其中的两座岛屿,“客户端”岛屿生产了一种农作物要运到“服务端”岛屿,所以“客户端”要知道“服务端”确切的地址(IP),不然就运错地方了,socket就相当于运输的船只,port就相当于“服务端”岛屿的某个港口。

(二)UDP网络编程

从技术意义上来讲,只有TCP才会分Server和Client。对于UDP来说,严格意义上,并没有所谓的Server和Client。
java.net包给我们提供了两个类DatagramSocket(此类表示用于发送和接收数据报的套接字)和DatagramPacket(该类表示数据报的数据包。 )

1.DatagramSocket
(1)构造方法摘要

protected DatagramSocket()构造数据报套接字并将其绑定到本地主机上的任何可用端口。
protected DatagramSocket(int port)构造数据报套接字并将其绑定到本地主机上的指定端口。
protected DatagramSocket(int port, InetAddress laddr)创建一个数据报套接字,绑定到指定的本地地址。

2.DatagramPacket
(1)构造方法摘要

DatagramPacket(byte[] buf, int offset, int length)构造一个 DatagramPacket用于接收指定长度的数据报包到缓冲区中。
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)构造用于发送指定长度的数据报包到指定主机的指定端口号上。

(2)常用方法摘要

byte[] getData() 返回数据报包中的数据。
InetAddress getAddress() 返回该数据报发送或接收数据报的计算机的IP地址。
int getLength() 返回要发送的数据的长度或接收到的数据的长度。

3.代码实现

案例演示1
发送方:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UDPSender {
    public static void main(String[] args) throws IOException {
        //1、创建一个socket
        DatagramSocket socket = new DatagramSocket();
        InetAddress inet = InetAddress.getLocalHost();
        String msg="你好,很高兴认识你!";
        byte[] buffer = msg.getBytes();
        //2、创建一个包(要发送给谁)
        DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length,inet,9090);
        //3、发送包
        socket.send(packet);
        //4、释放资源
        socket.close();
    }
}

接收方:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UDPReceiver {
    public static void main(String[] args) throws IOException {
        //1、创建一个socket,开放端口
        DatagramSocket socket = new DatagramSocket(9090);
        byte[] buffer = new byte[1024];
        //2、创建一个包接收数据
        DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
        //3、接收数据
        socket.receive(packet);//阻塞式接收
        //将数据包转换为字符串输出
        String msg = new String(packet.getData(), 0, packet.getLength());
        System.out.println(msg);
        //4、释放资源
        socket.close();
    }
}

在这里插入图片描述
注意
如果是TCP中先启动客户端会报错:
在这里插入图片描述
而如果是UDP中先启动发送方不会报错,但会正常退出。

案例演示2
完成在线咨询功能,学生和老师在线一对一交流(多线程

发送方:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

public class UDPSender implements Runnable{
    //创建一个socket
    DatagramSocket socket=null;
    //创建一个流 用于录入键盘的数据
    BufferedReader bfr=null;
    //发送数据目的地的IP
    private String toIP;
    //发送数据目的地的端口
    private int toPort;

    public UDPSender(String toIP, int toPort) {
        this.toIP = toIP;
        this.toPort = toPort;
        try {
            socket=new DatagramSocket();//创建一个socket
        } catch (SocketException e) {
            e.printStackTrace();
        }
        bfr=new BufferedReader(new InputStreamReader(System.in));//从键盘录入数据到流中
    }

    @Override
    public void run() {
        while (true){//循环发送数据
            try {
                String msg = bfr.readLine();//从流中读取数据
                byte[] buffer = msg.getBytes();
                InetAddress inet = InetAddress.getByName(toIP);
                DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length, inet, toPort);
                socket.send(packet);
                //如果发送了拜拜,则退出发送
                if(msg.equals("拜拜")){
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //释放资源
        if(socket!=null){
            socket.close();
        }
        if (bfr!=null){
            try {
                bfr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

接收方:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class UDPReceiver implements Runnable{
    //创建一个socket
    DatagramSocket socket=null;
    //接收方自己所在的端口
    private int fromPort;
    //数据发送者的姓名
    private String msgFrom;

    public UDPReceiver(int fromPort,String msgFrom) {
        this.fromPort = fromPort;
        this.msgFrom=msgFrom;
        try {
            socket=new DatagramSocket(fromPort);//创建一个socket
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        while(true){//循环接收
            try {
                byte[] buffer = new byte[1024 \* 8];
                DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
                socket.receive(packet);
                String msg = new String(packet.getData(), 0, packet.getLength());
                System.out.println(msgFrom+":"+msg);
                if (msg.equals("拜拜")){//如果接收到的数据为拜拜,则退出接收
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //释放资源
        socket.close();
    }
}

学生线程:

public class Student {
    public static void main(String[] args) {
        new Thread(new UDPSender("127.0.0.1",8888)).start();
        new Thread(new UDPReceiver(7777,"老师")).start();
    }
}

老师线程:

public class Teacher {
    public static void main(String[] args) {
        new Thread(new UDPSender("127.0.0.1",7777)).start();
        new Thread(new UDPReceiver(8888,"学生")).start();
    }
}


## 总结

> 这份面试题几乎包含了他在一年内遇到的所有面试题以及答案,甚至包括面试中的细节对话以及语录,可谓是细节到极致,甚至简历优化和怎么投简历更容易得到面试机会也包括在内!也包括教你怎么去获得一些大厂,比如阿里,腾讯的内推名额!


某位名人说过成功是靠99%的汗水和1%的机遇得到的,而你想获得那1%的机遇你首先就得付出99%的汗水!你只有朝着你的目标一步一步坚持不懈的走下去你才能有机会获得成功!

成功只会留给那些有准备的人!

![](https://img-blog.csdnimg.cn/img_convert/00c95d5835f908ff4d58d72a4939f7e5.webp?x-oss-process=image/format,png)

> **本文已被[CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】](https://bbs.youkuaiyun.com/topics/618154847)收录**

**[需要这份系统化的资料的朋友,可以点击这里获取](https://bbs.youkuaiyun.com/topics/618154847)**

 void main(String[] args) {
        new Thread(new UDPSender("127.0.0.1",8888)).start();
        new Thread(new UDPReceiver(7777,"老师")).start();
    }
}

老师线程:

public class Teacher {
    public static void main(String[] args) {
        new Thread(new UDPSender("127.0.0.1",7777)).start();
        new Thread(new UDPReceiver(8888,"学生")).start();
    }
}


## 总结

> 这份面试题几乎包含了他在一年内遇到的所有面试题以及答案,甚至包括面试中的细节对话以及语录,可谓是细节到极致,甚至简历优化和怎么投简历更容易得到面试机会也包括在内!也包括教你怎么去获得一些大厂,比如阿里,腾讯的内推名额!


某位名人说过成功是靠99%的汗水和1%的机遇得到的,而你想获得那1%的机遇你首先就得付出99%的汗水!你只有朝着你的目标一步一步坚持不懈的走下去你才能有机会获得成功!

成功只会留给那些有准备的人!

[外链图片转存中...(img-QZ040kGJ-1714839978442)]

> **本文已被[CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】](https://bbs.youkuaiyun.com/topics/618154847)收录**

**[需要这份系统化的资料的朋友,可以点击这里获取](https://bbs.youkuaiyun.com/topics/618154847)**

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值