Java实现UDP与TCP应用程序

news/2025/1/8 4:17:29/

三、Java实现UDP应用程序

3.1 InetAddress类

java.net.InteAddress类是用于描述IP地址和域名的一个Java类;

常用方法如下:

  • public static InetAddress getByName(String host):根据主机名获取InetAddress对象
  • public String getHostName():获取该对象对应的主机名
  • public String getHostAddress()获取该对象对应的IP地址

示例代码:

java">package com.dfbz.demo01_实现UDP;import java.net.InetAddress;
import java.net.UnknownHostException;/*** @author lscl* @version 1.0* @intro:*/
public class Demo01_InetAddress {public static void main(String[] args) throws UnknownHostException {// 根据域名获取InetAddress对象InetAddress localhost = InetAddress.getByName("localhost");// 获取主机名String hostName = localhost.getHostName();// 获取ip地址String hostAddress = localhost.getHostAddress();System.out.println(hostName);               // localhostSystem.out.println(hostAddress);            // 127.0.0.1System.out.println("-----------");InetAddress baidu = InetAddress.getByName("www.baidu.com");System.out.println(baidu.getHostName());        // www.baidu.comSystem.out.println(baidu.getHostAddress());     // 14.119.104.254}
}

3.2 DatagramPacket类

java.net.DatagramPacket是一种UDP协议的数据包结构,它包含源地址、目标地址和要传输的数据,用于封装一个UDP数据报文。

使用DatagramPacket,可以在应用程序之间发送和接收UDP数据包。

3.2.1 构造方法

  • public DatagramPacket(byte[] buf, int length, InetAddress address, int port):创建一个数据包对象
    • buf:要发送的内容
    • length:要发送的内容⻓度,单位字节
    • address:接收端的ip地址
    • port:接收端⼝号
  • public DatagramPacket(byte buf[], int length):创建一个数据包对象

示例代码:

java">package com.dfbz.demo01_实现UDP;import java.net.DatagramPacket;
import java.net.InetAddress;/*** @author lscl* @version 1.0* @intro:*/
public class Demo02_DatagramPacket_构造方法 {public static void main(String[] args) throws Exception {// 创建一个UDP报文用于发送DatagramPacket packet = new DatagramPacket("abc".getBytes(),                       // 报文封装的数据"abc".getBytes().length,                // 报文的数据长度InetAddress.getByName("localhost"),     // 接收端的地址8989                                    // 端口);// 创建一个UDP报文用于接收byte[] data = new byte[1024];DatagramPacket packet2 = new DatagramPacket(data,data.length);}
}

3.2.2 常用方法

  • public synchronized int getLength():获取此UDP数据包载荷的数据长度(单位字节)
  • public synchronized int getPort():获取此UDP数据包的目的端口号
  • public synchronized byte[] getData() :获取此UDP数据包的载荷部分(数据)

示例代码:

java">package com.dfbz.demo01_实现UDP;import java.net.DatagramPacket;
import java.net.InetAddress;/*** @author lscl* @version 1.0* @intro:*/
public class Demo03_DatagramPacket_成员方法 {public static void main(String[] args) throws Exception {// 创建一个UDP报文用于发送UDP报文DatagramPacket packet = new DatagramPacket("abc".getBytes(),"abc".getBytes().length,InetAddress.getByName("localhost"),8989);byte[] data = packet.getData();             // 获取UDP报文的数据int length = packet.getLength();            // 获取UDP报文的数据长度InetAddress address = packet.getAddress();  // 获取该UDP报文要发送的地址int port = packet.getPort();                // 获取该UDP报文要发送的端口System.out.println("getData(): " + new String(data));             // abcSystem.out.println("getLength(): " + length);                     // 3System.out.println("getAddress(): " + address.getHostAddress());  // 127.0.0.1System.out.println("getPort(): " + port);                         // 8989}
}

3.2 DatagramSocket类

java.net.DatagramSocket它提供了发送和接收UDP数据包的功能,用于描述一个UDP发送端或接收端;

在 Java 中,可以通过 DatagramSocket 类来创建一个套接字,并且可以通过 socket 的 receive 和 send 方法来发送和接收 UDP 数据包。这些方法提供了更好的灵活性,可以让您轻松地从多个地址和端口接收 UDP 数据包,并且可以选择性地发送数据包到特定地址和端口。 总的来说,DatagramSocket 是 UDP 协议的一种高级抽象,可以让您方便地在 Java 应用程序中发送和接收 UDP 数据包。

3.2.1 构造方法

  • public DatagramSocket(int port):通过端口构建一个发送端/接收端

示例代码:

java">DatagramSocket socket = new DatagramSocket(6969);

3.2.2 常用方法

  • public void send(DatagramPacket p):发送一个UDP数据包
  • public synchronized void receive(DatagramPacket p):接收一个UDP数据包
  • public void close():释放该Socket占用的资源

3.3 设计UDP应用程序

  • 发送端:
java">package com.dfbz.demo01_实现UDP;import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;/*** @author lscl* @version 1.0* @intro:*/
public class Demo04_发送端 {public static void main(String[] args) throws Exception {// 创建一个UDP报文的发送/接收器DatagramSocket socket = new DatagramSocket();// 封装一个UDP报文byte[] data = new byte[8192];DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName("localhost"), 9999);// 设置UDP报文的数据packet.setData("你好".getBytes());packet.setLength("你好".getBytes().length);// 发送UDP报文socket.send(packet);// 关闭资源socket.close();}
}
  • 接收端:
java">package com.dfbz.demo01_实现UDP;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;/*** @author lscl* @version 1.0* @intro:*/
public class Demo05_接收端 {public static void main(String[] args) throws IOException {// 创建一个UDP报文的发送/接收器DatagramSocket socket = new DatagramSocket(9999);// 创建一个UDP报文用于接收数据byte[] data = new byte[8192];DatagramPacket packet = new DatagramPacket(data, data.length);/*将socket接收到的UDP报文赋值给packet注意: 如果没有收到发送端的UDP报文,这一行代码将会阻塞当前线程的执行*/socket.receive(packet);socket.close();System.out.println("接收到了数据: " + new String(data, 0, packet.getLength()));}
}

四、Java实现TCP程序

在TCP通信中,分为数据的发送端(客户端)和接收端(服务器),当建立连接成功后(三次握手),才可以进行数据的发送;

在Java中,提供了两个类用于实现TCP通信程序:

  • 1)客户端:java.net.Socket 类表示;用于与服务器端建立连接,向服务器端发送数据报文等;
  • 2)服务端:java.net.ServerSocket 类表示;用于与客户端的交互;

4.1 Socket

java.net.Sokcet用于封装一个TCP应用程序的客户端;

4.1.1 构造方法

  • public Socket(String host, int port) :创建套接字对象并将其连接到指定主机上的指定端口号。如果指定的host是null ,则相当于指定地址为本机地址。

示例代码:

java">Socket client = new Socket("127.0.0.1", 6868);

4.1.2 成员方法

  • public InputStream getInputStream() : 返回此套接字的输入流。关闭生成的InputStream也将关闭相关的Socket。
  • public OutputStream getOutputStream() : 返回此套接字的输出流。关闭生成的OutputStream也将关闭相关的Socket。
  • public void close() :关闭此套接字。关闭此socket也将关闭相关的InputStream和OutputStream 。
  • public void shutdownOutput() : 禁用此套接字的输出流。任何先前写出的数据将被发送,随后终止输出流。

2.2 ServerSocket

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

4.2.1 构造方法

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

构造举例,代码如下:

java">ServerSocket server = new ServerSocket(6666);

4.2.2 成员方法

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

4.3 设计TCP应用程序

  • 客户端代码:
java">package com.dfbz.demo01_实现TCP;import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;/*** @author lscl* @version 1.0* @intro:*/
public class Demo01_客户端 {public static void main(String[] args) throws Exception {// 创建一个客户端Socket socket = new Socket("localhost", 6666);// 获取与服务器的输入流(用于读取服务器的数据)InputStream is = socket.getInputStream();// 获取与服务器的输出流(用于向服务器写出数据)OutputStream os = socket.getOutputStream();// 发送数据到服务器os.write("你好呀~!在吗?".getBytes());byte[] data = new byte[1024];/*读取服务器的数据注意: 如果没有接收到服务器的数据,这一行代码将会阻塞当前线程的执行*/int len = is.read(data);System.out.println("接收到来自服务器的信息【" + new String(data, 0, len) + "】");os.write("在干嘛?".getBytes());/*读取服务器的数据注意: 如果没有接收到服务器的数据,这一行代码将会阻塞当前线程的执行*/len = is.read(data);System.out.println("接收到来自服务器的信息【" + new String(data, 0, len) + "】");socket.close();}
}
  • 服务端代码:
java">package com.dfbz.demo01_实现TCP;import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;/*** @author lscl* @version 1.0* @intro:*/
public class Demo02_服务端 {public static void main(String[] args) throws Exception {// 创建了一个服务器ServerSocket serverSocket = new ServerSocket(6666);/*接收一个客户端注意: 如果没有客户端来连接服务器,这一行代码将会阻塞当前线程的执行*/Socket client = serverSocket.accept();// 获取与客户端的输入流(用于读取客户端的数据)InputStream is = client.getInputStream();// 获取与客户端的输出流(用于向客户端写出数据)OutputStream os = client.getOutputStream();byte[] data = new byte[1024];/*从客户端读取数据注意: 如果没有接收到客户端的数据,这一行代码将会阻塞当前线程的执行*/int len = is.read(data);System.out.println("接收到来自客户端的信息【" + new String(data, 0, len) + "】");os.write("在哦!".getBytes());/*从客户端读取数据注意: 如果没有接收到客户端的数据,这一行代码将会阻塞当前线程的执行*/len = is.read(data);System.out.println("接收到来自客户端的信息【" + new String(data, 0, len) + "】");os.write("在吃饭呢!".getBytes());// 关闭资源client.close();serverSocket.close();}
}

上述程序中,发送内容都是写死在代码中,我们使用Scanner来接受键盘录入的数据进行发送;

  • 改造客户端程序:
java">package com.dfbz.demo02_使用Scanner改造;import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;/*** @author lscl* @version 1.0* @intro:*/
public class Demo01_客户端 {public static void main(String[] args) throws Exception {// 创建一个客户端,并且去连接服务器Socket socket = new Socket("localhost", 7777);// 获取与服务器的输入/输出流(用于读取服务器的数据/向服务器写出数据)InputStream is = socket.getInputStream();OutputStream out = socket.getOutputStream();Scanner scanner = new Scanner(System.in);byte[] data = new byte[1024];while (true) {String str = scanner.nextLine();// 向服务器写出数据out.write(str.getBytes());// 读取服务器的信息int len = is.read(data);            // 这一句代码会造成阻塞,如果服务器没有向客户端写出数据,那么这一句代码阻塞System.out.println("来自服务器的信息【" + new String(data, 0, len) + "】");}}
}
  • 改造服务端程序:
java">package com.dfbz.demo02_使用Scanner改造;import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;/*** @author lscl* @version 1.0* @intro:*/
public class Demo02_服务端 {public static void main(String[] args) throws Exception {// 创建一个服务器ServerSocket serverSocket = new ServerSocket(7777);// 接收到一个客户端(这一段代码会造成阻塞,如果没有客户端来连接服务器,那么代码会一直阻塞在这里)Socket client = serverSocket.accept();// 获取这个客户端的ip地址String hostAddress = client.getInetAddress().getHostAddress();// 获取这个客户端的端口int port = client.getPort();// 获取与这个客户端的输入/输出流(用于与这个客户端的读写操作)InputStream is = client.getInputStream();OutputStream os = client.getOutputStream();Scanner scanner = new Scanner(System.in);byte[] data = new byte[1024];while (true) {// 读取这个客户端的信息(如果客户端没有发送数据过来,这句代码会造成阻塞)int len = is.read(data);System.out.println("" + "来自客户端【" + hostAddress + "】" + "端口为【" + port + "】" + "的应用程序发送的消息【" + new String(data, 0, len) + "】");// 接收控制台的数据. 同样的,如果控制台没有输入数据,那么这一行代码也会阻塞当前线程的执行String str = scanner.nextLine();os.write(str.getBytes());}}
}

五、综合案例

5.1 图片上传案例

5.2.1 UDP实现图片上传

UDP图片上传流程:

需要注意的是:由于UDP的特点(面向无连接、不安全等),因此采用UDP协议上传的图片会造成数据丢失,图片失真、丢失像素等问题;

【发送端】

java">package com.dfbz.demo01_图片上传;import java.io.FileInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;/*** @author lscl* @version 1.0* @intro:*/
public class Demo01_UDP_发送端 {public static void main(String[] args) throws Exception {// 创建一个套接字DatagramSocket socket = new DatagramSocket();// 从磁盘中读取文件FileInputStream fis = new FileInputStream("100.png");byte[] data = new byte[8192];// 创建一个UDP数据包DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName("localhost"), 9999);int len;while ((len = fis.read(data)) != -1) {// 将从磁盘中读取到的数据设置到UDP报文中packet.setData(data);packet.setLength(len);// 发送UDP报文给接收端socket.send(packet);}// 发送一个空报文,作为结束标识packet.setLength(0);socket.send(packet);// 释放资源fis.close();socket.close();}
}

【接收端】

java">package com.dfbz.demo01_图片上传;import java.io.FileOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;/*** @author lscl* @version 1.0* @intro:*/
public class Demo02_UDP_接收端 {public static void main(String[] args) throws Exception {// 创建一个套接字(用于接收UDP报文)DatagramSocket socket = new DatagramSocket(9999);byte[] data = new byte[8192];// 创建一个UDP数据包DatagramPacket packet = new DatagramPacket(data, data.length);// 创建一个文件输出流,将接收到的数据写入到这个文件中FileOutputStream fos = new FileOutputStream("udp.png");while (true) {// 接收UDP报文socket.receive(packet);// 获取报文数据长度int length = packet.getLength();if (length == 0) {// 说明读取到了末尾break;}fos.write(packet.getData(),0,length);}// 释放资源fos.close();socket.close();}
}

查看上传之前的原文件大小和上传之后的文件大小:

5.2.2 TCP实现图片上传

TCP图片上传流程:

1)客户端首先通过输入流将自己磁盘中的图片读取到内存中

2)客户端通过TCP连接的输出流,向服务器写出刚刚读取到的图片数据

3)服务器通过TCP连接的输入流,将客户端刚刚发送过来的图片数据读取到内存中

4)服务器通过输出流将内存中的数据写入到服务器的磁盘中

Tips:我们学习过程中,将服务器和客户端放在同一台机器。但实际开发中服务器和客户端不是在同一台机器,

【客户端代码实现】

java">package com.dfbz.demo02;import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;/*** @author lscl* @version 1.0* @intro:*/
public class Demo01_Server {public static void main(String[] args) throws Exception {// 声明服务器ServerSocket serverSocket = new ServerSocket(8888);// 接收到一个客户端Socket client = serverSocket.accept();System.out.println(client.getInetAddress().getHostAddress() + "连接成功");// 读取客户端传递过来的数据InputStream is = client.getInputStream();// 随机生成一个文件名写出到磁盘FileOutputStream fos = new FileOutputStream(UUID.randomUUID().toString() + ".png");byte[] data = new byte[1024];int len;while ((len = is.read(data)) != -1) {// 写出到磁盘fos.write(data, 0, len);}// 释放资源fos.close();client.close();}
}

【服务端代码实现】

java">package com.dfbz.demo01_图片上传;import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;/*** @author lscl* @version 1.0* @intro:*/
public class Demo04_TCP_服务端 {public static void main(String[] args) throws Exception {// 声明服务器ServerSocket serverSocket = new ServerSocket(8888);// 接收到一个客户端Socket client = serverSocket.accept();System.out.println(client.getInetAddress().getHostAddress() + "连接成功");// 读取客户端传递过来的数据InputStream is = client.getInputStream();// 随机生成一个文件名写出到磁盘FileOutputStream fos = new FileOutputStream("tcp.png");byte[] data = new byte[1024];int len;while ((len = is.read(data)) != -1) {// 写出到磁盘fos.write(data, 0, len);}// 释放资源fos.close();client.close();}
}

查看上传之前的原文件大小和上传之后的文件大小:

5.2.3 多线程改进TCP图片上传

实际开发中一个服务器对应N多个客户端,其他客户端均可以上传图片。我们的代码在同一时间只允许一个人上传图片,如果这个人上传的文件较大,那么势必会造成其他用户处于等待状态;针对这种情况我们可以使用多线程来解决。

服务器每次接受到一个客户端时,都开启一个线程来独立处理这个客户端的上传任务。这样在很多人同时来上传文件时,都可以一起上传。

  • 多线程改进服务器:
java">package com.dfbz.demo01_图片上传;import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;/*** @author lscl* @version 1.0* @intro:*/
public class Demo05_TCP_服务端_多线程 {public static void main(String[] args) throws Exception {// 创建一个服务器ServerSocket serverSocket = new ServerSocket(8888);while (true) {// 每接收到一个客户端都创建一个新的线程为它服务Socket client = serverSocket.accept();System.out.println("客户端【" + client.getInetAddress().getHostAddress() + "】连接成功啦!");new Thread() {@Overridepublic void run() {try {// 获取与客户端的输入流(用于读取客户端发送过来的字节)InputStream is = client.getInputStream();// 关联本地的一个文件(随机生成一个名称)FileOutputStream fos = new FileOutputStream(UUID.randomUUID() + ".png");byte[] data = new byte[8192];int len;while ((len = is.read(data)) != -1) {fos.write(data, 0, len);}fos.close();client.close();} catch (IOException e) {e.printStackTrace();}}}.start();}}
}

5.2 在线聊天案例

我们刚刚使用了TCP完成了聊天功能的编写;我们会发现我们的程序是由问题的,就是读写是串行的!

我们整个应用程序只有一个线程,那就mian线程,代码都是从上往下执行,如果main线程当前在读操作,那么就不能写。而且如果此时一方如果没有发送信息给另一方,那么另一方的read方法将会一直处于阻塞状态,代码不会往下执行;此时想往对方写出数据肯定是不行的;

我们利用多线程技术来改造我们之前的代码,让我们的代码既一直读,又可以一直写;

5.2.1 多线程UDP在线聊天案例

【多线程改进发送端】

java">package com.dfbz.demo02_多线程实现聊天案例;import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;/*** @author lscl* @version 1.0* @intro:*/
public class Demo01_UDP_发送端 {public static void main(String[] args) throws Exception {new Thread(() -> {try {// 1. 创建一个套接字,用于发送数据到接收端DatagramSocket socket = new DatagramSocket();// 2. 创建一个UDP报文,用于封装要发送到接收端的数据(接收端的端口为9999)byte[] data = new byte[8192];DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getLocalHost(), 9999);// 3. 死循环发送信息给接收端Scanner scanner = new Scanner(System.in);while (true) {// 接收键盘录入数据String line = scanner.nextLine();// 将数据设置到UDP报文中packet.setData(line.getBytes());packet.setLength(line.getBytes().length);// 将此UDP报文发送给接收端socket.send(packet);}} catch (Exception e) {e.printStackTrace();}}).start();new Thread(() -> {try {// 1. 创建一个套接字,用于接收来自接收端的数据(发送端的端口为7777)DatagramSocket socket = new DatagramSocket(7777);// 2. 创建一个UDP报文,用于接收来自接收端的数据byte[] data = new byte[8192];DatagramPacket packet = new DatagramPacket(data, data.length);// 3. 死循环接收来自接收端响应的信息while (true) {// 接收来自接收端的UDP报文socket.receive(packet);data = packet.getData();int len = packet.getLength();System.out.println("来自接收端【" + packet.getAddress().getHostAddress() + "】的信息: 【" + new String(data, 0, len) + "】");}} catch (Exception e) {e.printStackTrace();}}).start();}
}

【多线程改进接收端】

java">package com.dfbz.demo02_多线程实现聊天案例;import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;/*** @author lscl* @version 1.0* @intro:*/
public class Demo02_UDP_接收端 {public static void main(String[] args) throws Exception {// 接收端的读线程new Thread(() -> {try {// 1. 创建一个套接字,用于接收来自发送端的数据(接收端的端口为9999)DatagramSocket socket = new DatagramSocket(9999);// 2. 创建一个UDP报文,用于接收来自发送端的数据byte[] data = new byte[8192];DatagramPacket packet = new DatagramPacket(data, data.length);// 3. 死循环接收来自发送端响应的信息while (true) {// 接收来自发送端发送的UDP报文socket.receive(packet);data = packet.getData();int len = packet.getLength();System.out.println("来自发送端的【" + packet.getAddress().getHostAddress() + "】的信息: 【" + new String(data, 0, len) + "】");}} catch (Exception e) {e.printStackTrace();}}).start();// 接收端的写线程new Thread(() -> {try {// 1. 创建一个套接字,用于发送数据给发送端DatagramSocket socket = new DatagramSocket();// 2. 创建一个UDP报文,用于封装要发送到发送端的数据(发送端的端口为7777)byte[] data = new byte[8192];DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getLocalHost(), 7777);// 3. 死循环发送信息给发送端Scanner scanner = new Scanner(System.in);while (true) {// 接收键盘录入数据String line = scanner.nextLine();// 将数据设置到UDP报文中packet.setData(line.getBytes());packet.setLength(line.getBytes().length);// 将此UDP报文发送给发送端socket.send(packet);}} catch (Exception e) {e.printStackTrace();}}).start();}
}

5.2.2 多线程TCP在线聊天案例

【多线程改进客户端】

java">package com.dfbz.demo02_多线程实现聊天案例;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;/*** @author lscl* @version 1.0* @intro:*/
public class Demo03_TCP_客户端 {public static void main(String[] args) throws IOException {// 创建一个客户端,去连接服务器Socket socket = new Socket("127.0.0.1", 9999);// 获取与服务器的输入输出流InputStream is = socket.getInputStream();OutputStream os = socket.getOutputStream();// 读线程,专门用于读取服务器的信息new Thread() {@Overridepublic void run() {try {byte[] data = new byte[1024];while (true) {/*一直死循环读取服务器发送过来的数据如果服务器没有数据来也只是阻塞当前线程,并不会影响其他线程*/int len = is.read(data);System.out.println("接收到来自服务器的信息【" + new String(data, 0, len) + "】");}} catch (IOException e) {e.printStackTrace();}}}.start();// 写线程,专门向服务器写出数据new Thread() {@Overridepublic void run() {try {Scanner scanner = new Scanner(System.in);while (true) {/*一直死循环读取键盘录入的数据如果键盘没有输入数据,也只是阻塞当前线程,并不会影响其他线程*/String str = scanner.nextLine();os.write(str.getBytes());}} catch (IOException e) {e.printStackTrace();}}}.start();}
}

【多线程改进服务端】

java">package com.dfbz.demo02_多线程实现聊天案例;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;/*** @author lscl* @version 1.0* @intro:*/
public class Demo04_TCP_服务端 {public static void main(String[] args) throws Exception {// 创建一台服务器ServerSocket serverSocket = new ServerSocket(9999);// 接收一个客户端Socket client = serverSocket.accept();// 获取与这个客户端的输入输出流InputStream is = client.getInputStream();OutputStream os = client.getOutputStream();// 获取客户端的IP地址String hostAddress = client.getInetAddress().getHostAddress();// 获取客户端的应用程序端口int port = client.getPort();System.out.println("有一个客户端来连接了,地址【" + hostAddress + "】,端口【" + port + "】");// 读线程new Thread() {@Overridepublic void run() {try {byte[] data = new byte[1024];while (true) {/*一直死循环读取客户端发送过来的数据如果客户端没有数据来也只是阻塞当前线程,并不会影响其他线程*/int len = is.read(data);System.out.println("接收到了来自客户端【" + hostAddress + "】的信息【" + new String(data, 0, len) + "】");}} catch (IOException e) {e.printStackTrace();}}}.start();// 写线程new Thread() {@Overridepublic void run() {try {Scanner scanner = new Scanner(System.in);while (true) {/*一直死循环读取键盘录入的数据如果键盘没有输入数据,也只是阻塞当前线程,并不会影响其他线程*/String str = scanner.nextLine();os.write(str.getBytes());}} catch (IOException e) {e.printStackTrace();}}}.start();}
}

http://www.ppmy.cn/news/1560632.html

相关文章

【车载网络】BUSOFF状态简述和制造

BUSOFF Bus Off,即总线掉线,当前该节点脱离总线,不参与通信,可以理解为当前节点的Controller关闭,节点无法在此期间收/发报文。 注意,此期间ECU依然在正常运行,所有的任务依然被OS调度 TEC&am…

浏览器书签智能分类

浏览器书签智能分类工具 最近发现浏览器的书签越来越乱了,主要是因为自己太懒,其次之前建的分类太多又乱,重新手动整理确实比较烦。因此有了这个小项目。借助智谱AI的力量对书签进行重新分类。 项目简介 本工具用于自动整理浏览器书签&…

【ShuQiHere】算法的开枝散叶:从机器学习到深度学习的模型总结

【ShuQiHere】🚀 人工智能(AI)在过去十几年里经历了跨越式发展:从最初的计算机象征式推理到如今大行其道的深度学习,AI正逐步渗透到我们生活和工作的各个领域。然而,AI到底是如何一步步走到今天的&#xf…

AI数据标注师理论部分考试题库 - 500题

1.题目:职业道德是职场和行业内的特殊规范,这些规范是()在职业领域的具体实践。 A. 家庭道德 B. 社会道德 C. 仁义道德 D. 伦理道德 答案:B 解析:职业道德基于社会道德在职业场景的体现,与家庭、仁义、伦理道德概念不同,答案为 B。 2.题目:为了实现职业的健康发展,以…

python3中的字典推导式

一. 简介 前面简单学习了 python中的列表推导式,本文来简单学习一下 python中的字典推导式。 二. 字典推导式 python 中的字典推导式是 Python中创建字典的一种简洁方式。它允许你用一行代码来代替多行的 for循环和条件语句,从而快速地生成字典。 字典…

【LLM之评测】opencompass使用自定义接口与自定义数据集进行评测

🛠️ 安装指南 版本:0.3.7 下面提供了快速安装和数据集准备的步骤。 💻 环境搭建 强烈建议使用 conda 来管理您的 Python 环境。 创建虚拟环境 conda create --name opencompass python3.10 -y conda activate opencompass通过pip安装Ope…

React-Router 一站式攻略:从入门到精通,掌握路由搭建与权限管控

文章目录 一、前言二、安装使用 npm 安装(推荐)使用 yarn 安装 三、基础使用设置路由基础结构定义路由和组件关联直接在组件中定义路由定义单独一个路由表 创建导航链接 四、核心组件和功能BrowserRouter 和 HashRouterRoute 组件Link 组件Switch 组件 五…

《大话设计模式》解读09-建造者模式

上篇文章,介绍了《大话设计模式》的第12章——外观模式。 本篇,来介绍《大话设计模式》的第13章——建造者模式。并通过python代码实现示例代码的功能。 1 建造者模式 建造者模式(Builder):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。…