目录
一.网络通信三要素
1.三要素概述、要素一:IP地址
2.IP地址操作类-InetAddress
3.要素二:端口号
4.要素三:协议
二.UDP通信-快速入门
1.UDP通信:快速入门
2.UDP通信:多发多收
三.UDP通信-广播、组播
四.TCP通信-快速入门
1.编写客户端代码
2.编写服务端代码、原理分析
五.TCP通信-多发多收消息
六.TCP通信-同时接受多个客户端消息
七.TCP通信-使用线程池优化
八.TCP通信实战案例-即时通信
九.TCP通信实战案例-模拟BS系统
package com.wjh.d1_inetAddress;
/*
目标:
public static InetAddress getLocalHost() 返回本主机的地址对象
public static InetAddress getByName (String host) 得到指定主机的IP地址对象,参数是域名或者IP地址
public String getHostName() 获取此IP地址的主机名
public String getHostAddress() 返回IP地址字符串
public boolean isReachable(int timeout) 在指定毫秒内连通该IP地址对应的主机,连通返回true
*/
import java.net.InetAddress;
public class InetAddressDemo01 {
public static void main(String[] args) throws Exception{
//1.获取本机地址对象
InetAddress ip1 = InetAddress.getLocalHost();
System.out.println(ip1); //主机名/IP地址 -> (已封装toString,不打地址)
System.out.println(ip1.getHostName()); //主机名
System.out.println(ip1.getHostAddress()); //IP地址
//2.获取域名IP对象
InetAddress ip2 = InetAddress.getByName("www.baidu.com");
System.out.println(ip2); //www.baidu.com/14.119.104.254
//3.获取公网IP对象
InetAddress ip3 = InetAddress.getByName("14.119.104.254");
System.out.println(ip3.getHostName()); //14.119.104.254
System.out.println(ip3.getHostAddress()); //14.119.104.254
//4.判断是否能通:ping 5s之前测试是否可通
System.out.println(ip3.isReachable(5000)); //5s之后联通 -> true
}
}
wangjunhua/192.168.184.1
wangjunhua
192.168.184.1
www.baidu.com/14.119.104.189
14.119.104.254
14.119.104.254
true进程已结束,退出代码为 0
package com.wjh.d2_UDP1;
/*
发送端:(一发一收)
*/
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
public class ClientDemo1 {
public static void main(String[] args) throws Exception {
System.out.println("==========客户端启动=========");
//1.创建发送端对象:发送端口自带默认的端口号
DatagramSocket socket = new DatagramSocket();
//2.创建一个数据包对象封装数据(韭菜盘子)
/*
public DatagramPacket(byte buf[], int length,InetAddress address, int port) {
this(buf, 0, length, address, port); }
参数一:封装要发送的数据(韭菜)
参数二:发送数据的大小
参数三:服务端的IP地址
参数四:服务端的端口
*/
byte[] buffer = "回去下面给你吃?".getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getLocalHost(), 8889);
//3.发送数据出去
socket.send(packet);
socket.close();
}
}
package com.wjh.d2_UDP1;
/*
接受端:
*/
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class ServerDemo2 {
public static void main(String[] args) throws Exception {
System.out.println("==========服务端启动=========");
//1.创建接受端对象,注册端口(人)
DatagramSocket socket = new DatagramSocket(8889);
//2.创建一个数据包对象(韭菜盘子)
byte[] buffer = new byte[1024 * 64]; // 1KB * 64 = 64KB
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
//3.等待接受数据即可!
socket.receive(packet);
//4.取出数据即可
//读多少倒出多少
int len = packet.getLength();
String rs = new String(buffer,0, len);
System.out.println(rs+ " 数据已收到!");
socket.close();
//先启动服务端,再启动客户端
}
}
==========服务端启动=========
ps:(没有 "进程已结束,退出代码为 0" 提示:说明该进程没有断开,而是在等待......)
==========客户端启动=========
进程已结束,退出代码为 0
==========服务端启动=========
回去下面给你吃? 数据已收到!进程已结束,退出代码为 0
//获取发送端的IP和端口(在服务端写)
String ip = packet.getSocketAddress().toString();
System.out.println("来自IP地址 为:" + ip + "的数据!");
//来自 /192.168.184.1:50773 的数据!
int post = packet.getPort();
System.out.println("来自端口号为:" + post + "的数据!");
//来自端口号为:61849的数据!
package com.wjh.d2_UDP1;
/*
接受端:
*/
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class ServerDemo2 {
public static void main(String[] args) throws Exception {
System.out.println("==========服务端启动=========");
//1.创建接受端对象,注册端口(人)
DatagramSocket socket = new DatagramSocket(1256);
//2.创建一个数据包对象(韭菜盘子)
byte[] buffer = new byte[1024 * 64]; // 1KB * 64 = 64KB
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while (true) {
//3.等待接受数据即可!
socket.receive(packet);
//4.取出数据即可
//读多少倒出多少
int len = packet.getLength();
String rs = new String(buffer,0, len);
System.out.println(packet.getAddress().toString() + ",port:" + packet.getPort());
System.out.println(rs);
//socket.close();
}
//先启动服务端,再启动客户端
}
}
package com.wjh.d3_UDP2;
/*
发送端:(多发多收)
*/
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class ClientDemo1 {
public static void main(String[] args) throws Exception {
System.out.println("==========客户端启动=========");
//1.创建发送端对象:发送端口自带默认的端口号
DatagramSocket socket = new DatagramSocket(6569);
//2.创建一个数据包对象封装数据(韭菜盘子)
/*
public DatagramPacket(byte buf[], int length,InetAddress address, int port) {
this(buf, 0, length, address, port); }
参数一:封装要发送的数据(韭菜)
参数二:发送数据的大小ff
参数三:服务端的IP地址
参数四:服务端的端口
*/
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入要发送的数据内容:");
String str1 =sc.nextLine();
if("exit".equals(str1)){
System.out.println("离线成功!");
socket.close();
break;
}
byte[] buffer = str1.getBytes();
DatagramPacket packet = new DatagramPacket
(buffer, buffer.length, InetAddress.getLocalHost(), 1256);
//3.发送数据出去
socket.send(packet);
}
}
}
package com.wjh.d4_UDP3;
/*
发送端:(多发多收)
*/
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class ClientDemo1 {
public static void main(String[] args) throws Exception {
System.out.println("==========客户端启动=========");
//1.创建发送端对象:发送端口自带默认的端口号
DatagramSocket socket = new DatagramSocket(6569);
//2.创建一个数据包对象封装数据(韭菜盘子)
/*
public DatagramPacket(byte buf[], int length,InetAddress address, int port) {
this(buf, 0, length, address, port); }
参数一:封装要发送的数据(韭菜)
参数二:发送数据的大小ff
参数三:服务端的IP地址
参数四:服务端的端口
*/
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入要发送的数据内容:");
String str1 =sc.nextLine();
if("exit".equals(str1)){
System.out.println("离线成功!");
socket.close();
break;
}
byte[] buffer = str1.getBytes();
//广播消息
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("255.255.255.255"), 9999);
//组播消息
//3.发送数据出去
socket.send(packet);
}
}
}
package com.wjh.d2_UDP1;
/*
接受端:
*/
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class ServerDemo2 {
public static void main(String[] args) throws Exception {
System.out.println("==========服务端启动=========");
//1.创建接受端对象,注册端口(人)
DatagramSocket socket = new DatagramSocket(9999);
//2.创建一个数据包对象(韭菜盘子)
byte[] buffer = new byte[1024 * 64]; // 1KB * 64 = 64KB
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while (true) {
//3.等待接受数据即可!
socket.receive(packet);
//4.取出数据即可
//读多少倒出多少
int len = packet.getLength();
String rs = new String(buffer,0, len);
System.out.println(packet.getAddress().toString() + ",port:" + packet.getPort());
System.out.println(rs);
//socket.close();
}
//先启动服务端,再启动客户端
}
}
==========客户端启动=========
请输入要发送的数据内容:
我是一个广播消息
请输入要发送的数据内容:
==========服务端启动=========
/192.168.0.194,port:6569
我是一个广播消息
socket.joinGroup(new InetSocketAddress(InetAddress.getByName("224.0.1.1"),9998)
,NetworkInterface.getByInetAddress(InetAddress.getLocalHost()));
package com.wjh.d5_UDP4;
/*
发送端:(多发多收)
*/
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class ClientDemo1 {
public static void main(String[] args) throws Exception {
System.out.println("==========客户端启动=========");
//1.创建发送端对象:发送端口自带默认的端口号
DatagramSocket socket = new DatagramSocket(6569);
//2.创建一个数据包对象封装数据(韭菜盘子)
/*
public DatagramPacket(byte buf[], int length,InetAddress address, int port) {
this(buf, 0, length, address, port); }
参数一:封装要发送的数据(韭菜)
参数二:发送数据的大小ff
参数三:服务端的IP地址
参数四:服务端的端口
*/
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入要发送的数据内容:");
String str1 =sc.nextLine();
if("exit".equals(str1)){
System.out.println("离线成功!");
socket.close();
break;
}
byte[] buffer = str1.getBytes();
//广播消息
DatagramPacket packet = new DatagramPacket(buffer,
buffer.length, InetAddress.getByName("224.0.1.1"), 9998);
//组播消息
//3.发送数据出去
socket.send(packet);
}
}
}
package com.wjh.d2_UDP1;
/*
接受端:
*/
import java.net.*;
public class ServerDemo2 {
public static void main(String[] args) throws Exception {
System.out.println("==========服务端启动=========");
//1.创建接受端对象,注册端口(人)
MulticastSocket socket = new MulticastSocket(9998);
//把当前接受端加入到一个组播中去,绑定对应的组播消息的组播IP
//socket.joinGroup(InetAddress.getByName("224.0.1.1"));
socket.joinGroup(new InetSocketAddress(InetAddress.getByName("224.0.1.1"),9998)
,NetworkInterface.getByInetAddress(InetAddress.getLocalHost()));
//2.创建一个数据包对象(韭菜盘子)
byte[] buffer = new byte[1024 * 64]; // 1KB * 64 = 64KB
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while (true) {
//3.等待接受数据即可!
socket.receive(packet);
//4.取出数据即可
//读多少倒出多少
int len = packet.getLength();
String rs = new String(buffer,0, len);
System.out.println(packet.getAddress().toString() + ",port:" + packet.getPort());
System.out.println(rs);
//socket.close();
}
//先启动服务端,再启动客户端
}
}
==========客户端启动=========
请输入要发送的数据内容:
我是组播消息
请输入要发送的数据内容:
exit
离线成功!进程已结束,退出代码为 0
==========服务端启动=========
/192.168.0.194,port:6569
我是组播消息
package com.wjh.d5_socket1;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
/*
目标:完成socket网络编程入口案例客户端开发,实现一发一收
*/
public class ClientDemo1 {
public static void main(String[] args) throws Exception {
//1.创建socket通信管道请求服务端的连接
//public Socket(String, int port);
//参数一:服务端的IP地址
//参数二:服务端的端口号
Socket socket = new Socket("127.0.1", 7777);
//2.从socket通信管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
//3.把低级的字节流高级的打印流
PrintStream ps = new PrintStream(os);
//4.发送消息
ps.print("我是TCP的客户端,我已经与你对接,并发出邀请,约吗?");
ps.close();
//关闭资源
//socket.close();
}
}
package com.wjh.d5_socket1;
/*
目标:开发Service网络编程入门代码的服务端,实现接收数据
*/
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class ServiceDemo2 {
public static void main(String[] args) throws Exception{
System.out.println("=====服务端启动成功=====");
//1.注册端口
ServerSocket serverSocket = new ServerSocket(7778);
//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);
}
}
}
package com.wjh.d5_socket1;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
/*
目标:完成socket网络编程入口案例客户端开发,实现一发一收
*/
public class ClientDemo1 {
public static void main(String[] args) throws Exception {
System.out.println("=====客户端启动成功=====");
//1.创建socket通信管道请求服务端的连接
//public Socket(String, int port);
//参数一:服务端的IP地址
//参数二:服务端的端口号
Socket socket = new Socket("127.0.1", 7778);
//2.从socket通信管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
//3.把低级的字节流高级的打印流
PrintStream ps = new PrintStream(os);
//4.发送消息
//ps.print("我是TCP的客户端,我已经与你对接,并发出邀请,约吗?");
//注意:Connection reset -> 连接重置
ps.println("我是TCP的客户端,我已经与你对接,并发出邀请,约吗?");
ps.flush();
ps.close();
//关闭资源
//socket.close();
}
}
=====服务端启动成功=====
/127.0.0.1:64182说了:我是TCP的客户端,我已经与你对接,并发出邀请,约吗?进程已结束,退出代码为 0
=====客户端启动成功=====进程已结束,退出代码为 0
package com.wjh.d6_socket2.d5_socket1;
/*
目标:开发Service网络编程入门代码的服务端,实现接收数据
*/
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class ServiceDemo2 {
public static void main(String[] args) throws Exception{
System.out.println("=====服务端启动成功=====");
//1.注册端口
ServerSocket serverSocket = new ServerSocket(7778);
//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);
}
}
}
package com.wjh.d6_socket2.d5_socket1;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
/*
目标:完成socket网络编程入口案例客户端开发,实现多发多收
*/
public class ClientDemo1 {
public static void main(String[] args) throws Exception {
System.out.println("=====客户端启动成功=====");
//1.创建socket通信管道请求服务端的连接
//public Socket(String, int port);
//参数一:服务端的IP地址
//参数二:服务端的端口号
Socket socket = new Socket("127.0.1", 7778);
//2.从socket通信管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
//3.把低级的字节流高级的打印流
PrintStream ps = new PrintStream(os);
//4.发送消息
//ps.print("我是TCP的客户端,我已经与你对接,并发出邀请,约吗?");
//注意:Connection reset -> 连接重置
Scanner sc = new Scanner(System.in);
while (true){
System.out.println("请说:");
String msg = sc.nextLine();
ps.println(msg);
if ("exit".equals(msg)){
ps.flush();
break;
}
}
//关闭资源
//socket.close();
}
}
=====客户端启动成功=====
请说:
我是谁
请说:
在干嘛
请说:
啥都会
请说:
=====客户端启动成功=====
请说:
苏安安
请说:
=====服务端启动成功=====
/127.0.0.1:64857说了:我是谁
/127.0.0.1:64857说了:在干嘛
/127.0.0.1:64857说了:啥都会
package com.wjh.d7_socket3;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
/*
目标:完成socket网络编程入口案例客户端开发,实现多发多收
*/
public class ClientDemo1 {
public static void main(String[] args) throws Exception {
System.out.println("=====客户端启动成功=====");
//1.创建socket通信管道请求服务端的连接
//public Socket(String, int port);
//参数一:服务端的IP地址
//参数二:服务端的端口号
Socket socket = new Socket("127.0.1", 7771);
//2.从socket通信管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
//3.把低级的字节流高级的打印流
PrintStream ps = new PrintStream(os);
//4.发送消息
//ps.print("我是TCP的客户端,我已经与你对接,并发出邀请,约吗?");
//注意:Connection reset -> 连接重置
Scanner sc = new Scanner(System.in);
while (true){
System.out.println("请说:");
String msg = sc.nextLine();
ps.println(msg);
if ("exit".equals(msg)){
ps.flush();
break;
}
}
//关闭资源
//socket.close();
}
}
package com.wjh.d7_socket3;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
public class ServerReadThread extends Thread {
private Socket socket;
public ServerReadThread() {
}
public ServerReadThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
//3.从Socket通信管道中得到一个字节输入流
try {
InputStream is = socket.getInputStream();
//4.把字节输入流包装成缓冲字符输入流进行消息的接受
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//5.按照行读取消息
String msg;
while ((msg = br.readLine()) != null) {
System.out.println(Thread.currentThread().getName() + "线程" + socket.getRemoteSocketAddress() + "说了:" + msg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.wjh.d7_socket3;
/*
目标:实现服务端可以同时多个客户端连接
*/
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class ServiceDemo2 {
public static void main(String[] args) throws Exception{
System.out.println("=====服务端启动成功=====");
//1.注册端口
ServerSocket serverSocket = new ServerSocket(7771);
//a.定义一个死循环由主线程负责不断的接受客户端的Socket管道连接.
while (true) {
//2.每接受到一个客户端的socket管道,交给一个独立的子线程负责读取消息
Socket socket = serverSocket.accept();
//3.开始创建独立线程处理socket
new ServerReadThread(socket).start();
}
}
}
=====客户端启动成功=====
请说:
你好
请说:
=====客户端启动成功=====
请说:
在吗
请说:
=====客户端启动成功=====
请说:
在干嘛
请说:
=====客户端启动成功=====
请说:
略略略
请说:
=====服务端启动成功=====
Thread-0线程/127.0.0.1:50154说了:你好
Thread-1线程/127.0.0.1:50199说了:在吗
Thread-2线程/127.0.0.1:50213说了:在干嘛
Thread-3线程/127.0.0.1:50228说了:略略略
扩展:
try {
InputStream is = socket.getInputStream();
//4.把字节输入流包装成缓冲字符输入流进行消息的接受
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//5.按照行读取消息
String msg;
while ((msg = br.readLine()) != null) {
System.out.println(Thread.currentThread().getName() + "线程" + socket.getRemoteSocketAddress() + "说了:" + msg);
}
} catch (Exception e) {
System.out.println(socket.getRemoteSocketAddress() + "下线了");
}
while (true) {
//2.每接受到一个客户端的socket管道,交给一个独立的子线程负责读取消息
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress() + "它来了,上线了!");
//3.开始创建独立线程处理socket
new ServerReadThread(socket).start();
}
=====服务端启动成功=====
/127.0.0.1:50767它来了,上线了!
Thread-0线程/127.0.0.1:50767说了:阿斯顿发生
Thread-0线程/127.0.0.1:50767说了:按时gas
/127.0.0.1:50789它来了,上线了!
Thread-1线程/127.0.0.1:50789说了:sadgas
Thread-1线程/127.0.0.1:50789说了:dsgj
/127.0.0.1:50767下线了
/127.0.0.1:50789下线了
package com.wjh.d8_socket4;
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) throws Exception {
System.out.println("=====客户端启动成功=====");
//1.创建socket通信管道请求服务端的连接
//public Socket(String, int port);
//参数一:服务端的IP地址
//参数二:服务端的端口号
Socket socket = new Socket("127.0.0.1", 7771);
//2.从socket通信管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
//3.把低级的字节流高级的打印流
PrintStream ps = new PrintStream(os);
//4.发送消息
//ps.print("我是TCP的客户端,我已经与你对接,并发出邀请,约吗?");
//注意:Connection reset -> 连接重置
Scanner sc = new Scanner(System.in);
while (true){
System.out.println("请说:");
String msg = sc.nextLine();
ps.println(msg);
if ("exit".equals(msg)){
ps.flush();
break;
}
}
//关闭资源
//socket.close();
}
}
package com.wjh.d8_socket4;
/*
目标:实现服务端可以同时多个客户端连接
*/
import com.wjh.d7_socket3.ServerReadThread;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;
public class ServiceDemo2 {
//使用静态变量记住一个线程池对象
private static ExecutorService pool = new ThreadPoolExecutor(3, 5, 6, TimeUnit.SECONDS
, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) throws Exception{
System.out.println("=====服务端启动成功=====");
//1.注册端口
ServerSocket serverSocket = new ServerSocket(7771);
//a.定义一个死循环由主线程负责不断的接受客户端的Socket管道连接.
while (true) {
//2.每接受到一个客户端的socket管道,交给一个独立的子线程负责读取消息
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress() + "它来了,上线了!");
//做成任务交给线程池(负责处理消息)
Runnable target = new ServerReaderRunnable(socket);
pool.execute(target);
}
}
}
package com.wjh.d8_socket4;
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() {
}
public ServerReaderRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
InputStream is = socket.getInputStream();
//4.把字节输入流包装成缓冲字符输入流进行消息的接受
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//5.按照行读取消息
String msg;
while ((msg = br.readLine()) != null) {
System.out.println(Thread.currentThread().getName() + "线程" + socket.getRemoteSocketAddress() + "说了:" + msg);
}
} catch (Exception e) {
System.out.println(socket.getRemoteSocketAddress() + "下线了");
}
}
}
=====客户端启动成功=====
请说:
我是第二个线程
请说:
=====客户端启动成功=====
请说:
我是第三个线程
请说:
=====客户端启动成功=====
请说:
我是第四个线程
请说:
发送
请说:
我在消息队列
请说:
=====客户端启动成功=====
请说:
我是第五个线程
请说:
搜索
请说:
我在消息队列
请说:进程已结束,退出代码为 -1
=====客户端启动成功=====
请说:
我是第六个线程
请说:
我是第六个线程
请说:
我在消息队列
请说:
=====客户端启动成功=====
请说:
我是第六个线程
请说:
我是第六个线程
请说:
我在消息队列
请说:
=====客户端启动成功=====
请说:
我是第七个线程
请说:
哈哈哈,前面的朋友
请说:
我有临时线程给我服务,你们继续等待把
请说:
=====客户端启动成功=====
请说:
我是第八个线程
请说:
啦啦啦
请说:
哎呦,这么多人啊
请说:
我先进去了
请说:
=====客户端启动成功=====
请说:
我是第九个线程
请说:
我去
请说:
???
请说:
报错了
请说:
=====服务端启动成功=====
/127.0.0.1:52268它来了,上线了!
pool-1-thread-1线程/127.0.0.1:52268说了:我是第一个线程
/127.0.0.1:52296它来了,上线了!
pool-1-thread-2线程/127.0.0.1:52296说了:我是第二个线程
/127.0.0.1:52314它来了,上线了!
pool-1-thread-3线程/127.0.0.1:52314说了:我是第三个线程
/127.0.0.1:52327它来了,上线了!
/127.0.0.1:52268下线了
pool-1-thread-1线程/127.0.0.1:52327说了:我是第四个线程,由于我不是主线程,3个主线程都在忙,所以你收不到我的消息
pool-1-thread-1线程/127.0.0.1:52327说了:但是能看到我的上下线状态
pool-1-thread-1线程/127.0.0.1:52327说了:有一个线程关闭了
pool-1-thread-1线程/127.0.0.1:52327说了:我可以发送消息了
pool-1-thread-1线程/127.0.0.1:52327说了:现在我是第三个线程了
/127.0.0.1:52581它来了,上线了!
/127.0.0.1:52596它来了,上线了!
/127.0.0.1:52623它来了,上线了!
/127.0.0.1:52691它来了,上线了!
pool-1-thread-4线程/127.0.0.1:52691说了:我是第七个线程
pool-1-thread-4线程/127.0.0.1:52691说了:哈哈哈,前面的朋友
pool-1-thread-4线程/127.0.0.1:52691说了:我有临时线程给我服务,你们继续等待把
/127.0.0.1:52805它来了,上线了!
pool-1-thread-5线程/127.0.0.1:52805说了:我是第八个线程
pool-1-thread-5线程/127.0.0.1:52805说了:啦啦啦
pool-1-thread-5线程/127.0.0.1:52805说了:哎呦,这么多人啊
pool-1-thread-5线程/127.0.0.1:52805说了:我先进去了
/127.0.0.1:52856它来了,上线了!
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.wjh.d8_socket4.ServerReaderRunnable@52cc8049 rejected from java.util.concurrent.ThreadPoolExecutor@5b6f7412[Running, pool size = 5, active threads = 5, queued tasks = 3, completed tasks = 1]
at java.base/java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2065)
at java.base/java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:833)
at java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1365)
at com.wjh.d8_socket4.ServiceDemo2.main(ServiceDemo2.java:32)
PS:由于代码抛异常时选择的直接抛,后面除了异常就会干掉程序,所以建议大家使用规范的try{ }catch{ }处理异常.
还有如果队列里的线程下线了,第四个线程的任务会被立即执行!
package com.wjh.d10_bs;
/*
*/
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;
public class BSServerDemo {
//使用静态变量记住一个线程池对象
private static ExecutorService pool = new ThreadPoolExecutor(3, 5, 6, TimeUnit.SECONDS
, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) {
//1.注册端口
try {
ServerSocket ss = new ServerSocket(8080);
//2.创建一个循环接受多个客户端的请求
while (true) {
Socket socket = ss.accept();
//3.交给一个独立的线程来处理!
pool.execute(new ServerReaderRunnable(socket));
}
} catch (Exception e) {
e.printStackTrace();
}
}
static class ServerReaderThread extends Thread {
private Socket socket;
public ServerReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
//浏览器 已经与本线程建立了Socket管道
//响应消息给浏览器显示
PrintStream ps = null;
try {
ps = new PrintStream(socket.getOutputStream());
//必须响应HTTP协议数据格式,否则浏览器不认识消息
ps.println("HTTP/1.1 200 OK"); //协议类型和版本 响应成功的消息
ps.println("Content-Type:text/html;charset=UTF-8");
ps.println(); //必须发送一个空行
//才可以响应数据回去给浏览器
ps.println("最牛的ikun");
ps.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}