Java基础——TCP通信

news/2024/11/30 13:41:51/

(1)TCP协议特点:

  • TCP是一种面向连接,安全,可靠的传输数据的协议
  • 传输前,采用“三次握手”方式,点对点通信,是可靠的
  • 在连接中可进行大数据量的传输

(2) TCP通信模式:(在java中只需使用java.net.Socket类实现通信,底层即是使用了TCP协议)

2.1:一发一收

客户端 (一发一收)

import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;/**目标:完成Socket网络编程入门案例的客户端开发,实现1发1收。*/
public class ClientDemo1 {public static void main(String[] args) {try {System.out.println("====客户端启动===");// 1、创建Socket通信管道请求有服务端的连接// public Socket(String host, int port)// 参数一:服务端的IP地址// 参数二:服务端的端口Socket socket = new Socket("127.0.0.1", 7777);// 2、从socket通信管道中得到一个字节输出流 负责发送数据OutputStream os = socket.getOutputStream();// 3、把低级的字节流包装成打印流PrintStream ps = new PrintStream(os);// 4、发送消息ps.println("我是TCP的客户端,我已经与你对接,并发出邀请:约吗?");ps.flush();// 关闭资源。// socket.close();} catch (Exception e) {e.printStackTrace();}}
}

服务端(一发一收)

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;/**目标:开发Socket网络编程入门代码的服务端,实现接收消息*/
public class ServerDemo2 {public static void main(String[] args) {try {System.out.println("===服务端启动成功===");// 1、注册端口ServerSocket serverSocket = new ServerSocket(7777);// 2、必须调用accept方法:等待接收客户端的Socket连接请求,建立Socket通信管道Socket socket = serverSocket.accept();// 3、从socket通信管道中得到一个字节输入流InputStream is = socket.getInputStream();// 4、把字节输入流包装成缓冲字符输入流进行消息的接收BufferedReader br = new BufferedReader(new InputStreamReader(is));// 5、按照行读取消息String msg;if ((msg = br.readLine()) != null){System.out.println(socket.getRemoteSocketAddress() + "说了:: " + msg);}} catch (Exception e) {e.printStackTrace();}}
}

2.2:多发多收(单线程)

注意:目前的服务端不可以同时接收多个客户端的信息,因为目前服务端现在只有一个线程,只能与一个客户端进行通信。

客户端(多发多收:单线程,使用循环反复地发送消息)

import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;/**目标:实现多发和多收*/
public class ClientDemo1 {public static void main(String[] args) {try {System.out.println("====客户端启动===");// 1、创建Socket通信管道请求有服务端的连接// public Socket(String host, int port)// 参数一:服务端的IP地址// 参数二:服务端的端口Socket socket = new Socket("127.0.0.1", 7777);// 2、从socket通信管道中得到一个字节输出流 负责发送数据OutputStream os = socket.getOutputStream();// 3、把低级的字节流包装成打印流PrintStream ps = new PrintStream(os);Scanner sc =  new Scanner(System.in);while (true) {System.out.println("请说:");String msg = sc.nextLine();// 4、发送消息ps.println(msg);ps.flush();}// 关闭资源。// socket.close();} catch (Exception e) {e.printStackTrace();}}
}

服务端(多发多收:单线程,使用循环反复的接收消息)

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;/**目标:开发Socket网络编程入门代码的服务端,实现接收消息*/
public class ServerDemo2 {public static void main(String[] args) {try {System.out.println("===服务端启动成功===");// 1、注册端口ServerSocket serverSocket = new ServerSocket(7777);while (true) {// 2、必须调用accept方法:等待接收客户端的Socket连接请求,建立Socket通信管道Socket socket = serverSocket.accept();// 3、从socket通信管道中得到一个字节输入流InputStream is = socket.getInputStream();// 4、把字节输入流包装成缓冲字符输入流进行消息的接收BufferedReader br = new BufferedReader(new InputStreamReader(is));// 5、按照行读取消息String msg;while ((msg = br.readLine()) != null){System.out.println(socket.getRemoteSocketAddress() + "说了:: " + msg);}}} catch (Exception e) {e.printStackTrace();}}
}

2.3:多发多收(多线程)

客户端(多发多收:多线程) 

import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;/**目标:实现服务端可以同时处理多个客户端的消息。*/
public class ClientDemo3 {public static void main(String[] args) {try {System.out.println("====客户端启动===");// 1、创建Socket通信管道请求有服务端的连接// public Socket(String host, int port)// 参数一:服务端的IP地址// 参数二:服务端的端口Socket socket = new Socket("127.0.0.1", 7777);// 2、从socket通信管道中得到一个字节输出流 负责发送数据OutputStream os = socket.getOutputStream();// 3、把低级的字节流包装成打印流PrintStream ps = new PrintStream(os);Scanner sc =  new Scanner(System.in);while (true) {System.out.println("请说:");String msg = sc.nextLine();// 4、发送消息ps.println(msg);ps.flush();}// 关闭资源。// socket.close();} catch (Exception e) {e.printStackTrace();}}
}

服务端(多发多收:多线程) 

import java.net.ServerSocket;
import java.net.Socket;/**目标:实现服务端可以同时处理多个客户端的消息。*/
public class ServerDemo3 {public static void main(String[] args) {try {System.out.println("===服务端启动成功===");// 1、注册端口ServerSocket serverSocket = new ServerSocket(7777);// a.定义一个死循环由主线程负责不断的接收客户端的Socket管道连接。while (true) {// 2、每接收到一个客户端的Socket管道,交给一个独立的子线程负责读取消息Socket socket = serverSocket.accept();System.out.println(socket.getRemoteSocketAddress()+ "它来了,上线了!");// 3、开始创建独立线程处理socketnew ServerReaderThread(socket).start();}} catch (Exception e) {e.printStackTrace();}}
}

(定义一个线程类)

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;public class ServerReaderThread extends Thread{private Socket socket;public ServerReaderThread(Socket socket){this.socket = socket;}@Overridepublic void run() {try {// 3、从socket通信管道中得到一个字节输入流InputStream is = socket.getInputStream();// 4、把字节输入流包装成缓冲字符输入流进行消息的接收BufferedReader br = new BufferedReader(new InputStreamReader(is));// 5、按照行读取消息String msg;while ((msg = br.readLine()) != null){System.out.println(socket.getRemoteSocketAddress() + "说了:: " + msg);}} catch (Exception e) {System.out.println(socket.getRemoteSocketAddress() + "下线了!!!");}}
}

2.4:线程池

服务端可以复用线程处理多个客户端,可以避免系统瘫痪。

适合客户端通信时长较短的场景。

客户端(线程池:处理多个客户端消息,解决多线程N-N的关系,导致资源浪费的问题)

import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;/**拓展:使用线程池优化:实现通信。*/
public class ClientDemo4 {public static void main(String[] args) {try {System.out.println("====客户端启动===");// 1、创建Socket通信管道请求有服务端的连接// public Socket(String host, int port)// 参数一:服务端的IP地址// 参数二:服务端的端口Socket socket = new Socket("127.0.0.1", 6666);// 2、从socket通信管道中得到一个字节输出流 负责发送数据OutputStream os = socket.getOutputStream();// 3、把低级的字节流包装成打印流PrintStream ps = new PrintStream(os);Scanner sc =  new Scanner(System.in);while (true) {System.out.println("请说:");String msg = sc.nextLine();// 4、发送消息ps.println(msg);ps.flush();}// 关闭资源。// socket.close();} catch (Exception e) {e.printStackTrace();}}
}

 2.8服务端(线程池:处理多个客户端消息,解决多线程N-N的关系,导致资源浪费的问题)

import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;/**目标:实现服务端可以同时处理多个客户端的消息。*/
public class ServerDemo4 {// 使用静态变量记住一个线程池对象private static ExecutorService pool = new ThreadPoolExecutor(300,1500, 6, TimeUnit.SECONDS,new ArrayBlockingQueue<>(2), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());public static void main(String[] args) {try {System.out.println("===服务端启动成功===");// 1、注册端口ServerSocket serverSocket = new ServerSocket(6666);// a.定义一个死循环由主线程负责不断的接收客户端的Socket管道连接。while (true) {// 2、每接收到一个客户端的Socket管道,Socket socket = serverSocket.accept();System.out.println(socket.getRemoteSocketAddress()+ "它来了,上线了!");// 任务对象负责读取消息。Runnable target = new ServerReaderRunnable(socket);pool.execute(target);}} catch (Exception e) {e.printStackTrace();}}
}

(定义一个任务类) 

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;public class ServerReaderRunnable implements Runnable{private Socket socket;public ServerReaderRunnable(Socket socket){this.socket = socket;}@Overridepublic void run() {try {// 3、从socket通信管道中得到一个字节输入流InputStream is = socket.getInputStream();// 4、把字节输入流包装成缓冲字符输入流进行消息的接收BufferedReader br = new BufferedReader(new InputStreamReader(is));// 5、按照行读取消息String msg;while ((msg = br.readLine()) != null){System.out.println(socket.getRemoteSocketAddress() + "说了:: " + msg);}} catch (Exception e) {System.out.println(socket.getRemoteSocketAddress() + "下线了!!!");}}
}


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

相关文章

想保护你的网站?用Python来生成验证码图片

前言 随着互联网的发展&#xff0c;我们越来越多地依赖于网站和应用程序&#xff0c;而这些网站和应用程序也面临着各种各样的安全威胁&#xff0c;其中之一就是用户可能会通过脚本攻击你的网站。为了缓解这些安全风险&#xff0c;一个常见的做法是在用户进行操作时&#xff0…

音视频 FFmpeg

文章目录 前言视频编解码硬件解码(高级)软解码(低级)软、硬解码对比视频解码有四个步骤Android 系统中编解码器的命名方式查看当前设备支持的硬解码 基础知识RGB色彩空间常见的格式对比YUV索引格式分离RGB24像素数据中的R、G、B分量 BMP 文件格式格式组成像素排列顺序RGB24格式…

【Ubuntu18.04使用yolov5教程】

欢迎大家阅读2345VOR的博客【Ubuntu18.04使用yolov5教程】&#x1f973;&#x1f973;&#x1f973;2345VOR鹏鹏主页&#xff1a; 已获得CSDN《嵌入式领域优质创作者》称号&#x1f47b;&#x1f47b;&#x1f47b;&#xff0c;座右铭&#xff1a;脚踏实地&#xff0c;仰望星空…

Spark大数据处理讲课笔记3.3 掌握RDD分区

文章目录 零、本讲学习目标一、RRD分区&#xff08;一&#xff09;RDD分区概念&#xff08;二&#xff09;RDD分区作用 二、RDD分区数量&#xff08;一&#xff09;RDD分区原则&#xff08;二&#xff09;影响分区的因素&#xff08;三&#xff09;使用parallelize()方法创建RD…

pandas使用教程:apply函数、聚合函数agg和transform

文章目录 apply函数调用apply函数描述性统计apply函数lambda自定义 聚合函数aggregate/agg用字典实现聚合 transform函数多函数 Transform 重置索引与更换标签行重置索引行和列同时重置索引 apply函数调用 apply函数描述性统计 import numpy as np df.loc[:,Q1:Q4].apply(np.…

【C++】线程库

文章目录 线程库&#xff08;thread&#xff09;线程安全锁实现两个线程交替打印1-100 线程库&#xff08;thread&#xff09; 在C11之前&#xff0c;涉及到多线程问题&#xff0c;都是和平台相关的&#xff0c;比如Windows和Linux下各有自己的接口&#xff0c;这使得代码的可…

SpringBoot日志文件

日升时奋斗&#xff0c;日落时自省 目录 1、日志功能 2、SpringBoot内置日志框架 3、日志打印 3.1、日志格式说明 3.2、手动打印日志 4、日志级别 4.1、级别的作用 4.2、日志级别的分类和使用 4.3、日志打印 4.3.1、类进行日志打印 4.3.2、类名进行日志打印 4.4、…

Linux网络编程:三次握手 四次挥手

1. 三次握手 建立TCP可靠连接&#xff0c;只能是客户端先发起。 &#xff08;1&#xff09;SYN标志位为1&#xff0c;表示请求建立连接&#xff1b;ACK标志位为1&#xff0c;表示确认收到对方报文。 &#xff08;2&#xff09;seq为数据包序列号&#xff0c;ack为确认序列号。…