第一节:网络编程02
三. UDP通信过程
【1】发送Send
- 创建DatagramSocket, 随机端口号
- 创建DatagramPacket, 指定数据, 长度, 地址, 端口
- 使用DatagramSocket发送DatagramPacket
- 关闭DatagramSocket
【2】接收Receive
- String ip = packet.getAddress().getHostAddress();
- int port = packet.getPort();
1. 具体实现细节(案例)
目的:让一个发送端发送数据,接收端接受数据。
发送方
注意:发送数据必须封装成DatagramPacket
/**
* 发送端
* 1. 使用DatagramSocket 指定端口 创建发送端
* 2. 准备数据 转成字节数组
* 3.封装成DatagramPacket包裹,需要指定目的地
* 4.发送包裹send(DatagramPacket p)
* 5.释放资源
*/
public class UDPClient {
public static void main(String[] args) throws Exception{
System.out.println("发送方启动中.....");
//1. 使用DatagramSocket 指定端口 创建发送端
DatagramSocket client = new DatagramSocket(8888);
//2. 准备数据 转成字节数组
byte [] datas = "你好java".getBytes();
//3.封装成DatagramPacket包裹,需要指定目的地,送往端口号为:9999
DatagramPacket packet = new DatagramPacket(datas,0,datas.length,
new InetSocketAddress("localhost",9999));
//4.发送包裹send(DatagramPacket p)
client.send(packet);
//5.释放资源
client.close();
}
}
接受端
注意:接受端必须对发送端的数据进行解析
/**
* 接受端 Address already in use: bind 同一个协议下端口号不允许冲突
* 1. 使用DatagramSocket 指定端口 创建接受端
* 2. 准备容器 封装成DatagramPacket包裹
* 3.阻塞式接受包裹 void receive(DatagramPacket p)
* 4.分析数据
* byte[] getData()
* int getLength()
* 5.释放资源
*/
public class UDPServer {
public static void main(String[] args) throws Exception{
System.out.println("接受方启动中.....");
// 1. 使用DatagramSocket 指定端口 创建接受端
DatagramSocket server = new DatagramSocket(9999);
// 2. 准备容器 封装成DatagramPacket包裹
byte[] container = new byte[1024*60];
DatagramPacket packet = new DatagramPacket(container,0,container.length);
//3.阻塞式接受包裹 void receive(DatagramPacket p)
server.receive(packet);
//4.分析数据
// byte[] getData()
// int getLength()
byte [] datas = packet.getData();
int len = packet.getLength();
System.out.println(new String(datas,0,len));
//5.释放资源
server.close();
}
}
2. 多次发送与多次接受(案例)
目的:让发送端多次发送数据,接收端多次接受数据。
接收端
public class UDPServer {
public static void main(String[] args) throws Exception{
//1. 使用DatagramSocket 指定端口 创建接受端
DatagramSocket server = new DatagramSocket(9999);
//2. 准备容器 封装成DatagramPacket包裹
byte[] container = new byte[1024*60];
DatagramPacket packet = new DatagramPacket(container,0,container.length);
//3.阻塞式接受包裹 void receive(DatagramPacket p)
while (true){
server.receive(packet);
//4.分析数据
// byte[] getData()
// int getLength()
byte[] datas = packet.getData();
int len = packet.getLength();
String data = new String(datas,0,len);
System.out.println(data);
if (data.equals("bye")){
break;
}
}
//5.释放资源
server.close();
}
}
发送端
/*
发送端可以利用控制台向接收端发送多次
*/
public class UDPClient {
public static void main(String[] args) throws Exception{
System.out.println("发送方启动中.....");
//1. 使用DatagramSocket 指定端口 创建发送端
DatagramSocket client = new DatagramSocket(8888);
//2. 准备数据 转成字节数组
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true){
//3.封装成DatagramPacket包裹,需要指定目的地
String data = reader.readLine();
byte[] datas = data.getBytes();
DatagramPacket packet = new DatagramPacket(datas,0,datas.length,
new InetSocketAddress("localhost",9999));
//4.发送包裹send(DatagramPacket p)
client.send(packet);
if (data.equals("bye")) {
break;
}
}
//5.释放资源
client.close();
}
}
3. 让一个客户与另一个客户通信。
目的:每个客户都具有发送和接受功能
客户一
注意:客户一的自身端口号为:7777,发往的端口号为:9999,接收数据的端口号为:9999.
/*
采用多线程的方式,使得任何一个客户端都能够收发数据
两个线程:
一个线程负责接受
一个线程负责发
*/
public class UDPSend {
public static void main(String[] args) { //确定自身端口号为:7777,送往端口号9999,接受数据的端口号8888
/*
先做一个发的线程
*/
new Thread(new Runnable() {
@Override
public void run() {
//1. 使用DatagramSocket 指定端口 创建发送端
DatagramSocket client = null;
try {
client = new DatagramSocket(7777);
//2. 准备数据 转成字节数组
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true){
//3.封装成DatagramPacket包裹,需要指定目的地
String data = reader.readLine();
byte[] datas = data.getBytes();
DatagramPacket packet = new DatagramPacket(datas,0,datas.length,
new InetSocketAddress("localhost",9999));
//4.发送包裹send(DatagramPacket p)
client.send(packet);
if (data.equals("bye")) {
break;
}
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
//5.释放资源
client.close();
}
}
}).start();
/*
再做一个收的线程
*/
new Thread(new Runnable() {
@Override
public void run() {
//1. 使用DatagramSocket 指定端口 创建接受端
DatagramSocket server = null;
try {
server = new DatagramSocket(8888);
//2. 准备容器 封装成DatagramPacket包裹
byte[] container = new byte[1024*60];
DatagramPacket packet = new DatagramPacket(container,0,container.length);
//3.阻塞式接受包裹 void receive(DatagramPacket p)
while (true){
server.receive(packet);
//4.分析数据
// byte[] getData()
// int getLength()
byte[] datas = packet.getData();
int len = packet.getLength();
String data = new String(datas,0,len);
System.out.println("老师说:" + data);
if (data.equals("bye")){
break;
}
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
//5.释放资源
server.close();
}
}
}).start();
}
}
客户二
注意:客户二自身端口号为:5555,发往端口号8888,接收数据端口号9999
public class UDPReceive {
public static void main(String[] args) { //确定自身端口号为:5555,发往端口号8888,接收数据端口号9999
/*
先做一个发的线程
*/
new Thread(new Runnable() {
@Override
public void run() {
//1. 使用DatagramSocket 指定端口 创建发送端
DatagramSocket client = null;
try {
client = new DatagramSocket(5555);
//2. 准备数据 转成字节数组
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true){
//3.封装成DatagramPacket包裹,需要指定目的地
String data = reader.readLine();
byte[] datas = data.getBytes();
DatagramPacket packet = new DatagramPacket(datas,0,datas.length,
new InetSocketAddress("localhost",8888));
//4.发送包裹send(DatagramPacket p)
client.send(packet);
if (data.equals("bye")) {
break;
}
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
//5.释放资源
client.close();
}
}
}).start();
/*
再做一个收的线程
*/
new Thread(new Runnable() {
@Override
public void run() {
//1. 使用DatagramSocket 指定端口 创建接受端
DatagramSocket server = null;
try {
server = new DatagramSocket(9999);
//2. 准备容器 封装成DatagramPacket包裹
byte[] container = new byte[1024*60];
DatagramPacket packet = new DatagramPacket(container,0,container.length);
//3.阻塞式接受包裹 void receive(DatagramPacket p)
while (true){
server.receive(packet);
//4.分析数据
// byte[] getData()
// int getLength()
byte[] datas = packet.getData();
int len = packet.getLength();
String data = new String(datas,0,len);
System.out.println("学生说:" + data);
if (data.equals("bye")){
break;
}
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
//5.释放资源
server.close();
}
}
}).start();
}
}
四. 采用TCP通信原理,实现一个简单的群聊案例。
1. 第一版:实现一个客户可以收发一条消息。
服务端
/**
* 在线聊天室:服务器
* 目标:实现一个客户可以正常收发信息
*/
public class Chat {
public static void main(String[] args) throws Exception{
System.out.println("----------Server------------");
//1.指定端口 使用ServerSocket创建服务器
ServerSocket server = new ServerSocket(8888);
//2.阻塞式等待连接accept
Socket client = server.accept();
System.out.println("一个客户建立了连接");
//3.接受消息
DataInputStream dis = new DataInputStream(client.getInputStream());
String msg = dis.readUTF();
//4.返回消息
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
dos.writeUTF(msg);
dos.flush();
//释放资源
dos.close();
dis.close();
server.close();
}
}
客户端
public class Client {
public static void main(String[] args) throws Exception{
System.out.println("------Client--------");
//1.创建一个客户端Socket对象,构造方法中绑定服务器的IP地址和端口号
Socket client = new Socket("localhost",8888);
//2. 客户端发送消息
BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
String msg = console.readLine();
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
dos.writeUTF(msg);
dos.flush();
//3.获取消息
DataInputStream dis = new DataInputStream(client.getInputStream());
msg = dis.readUTF();
System.out.println(msg);
//释放资源
dos.close();
dis.close();
client.close();
}
}
存在问题:虽然可以客户端和服务器可以连通,但是只能收发一条消息。
解决方法:采用While循环的方式,实现可以收发多条消息。
2. 第二版:实现一个客户可以收发多条消息。
/**
* 在线聊天室:服务器
* 目标:实现一个客户可以正常收发多条信息
*/
public class MultiChat {
public static void main(String[] args) throws Exception{
System.out.println("----------Server------------");
//1.指定端口 使用ServerSocket创建服务器
ServerSocket server = new ServerSocket(8888);
//2.阻塞式等待连接accept
Socket client = server.accept();
DataInputStream dis = new DataInputStream(client.getInputStream());
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
System.out.println("一个客户建立了连接");
boolean isRunning = true;
while (isRunning){
//3.接受消息
String msg = dis.readUTF();
//4.返回消息
dos.writeUTF(msg);
}
dos.flush();
//释放资源
dos.close();
dis.close();
server.close();
}
}
public class MultiClient {
public static void main(String[] args) throws Exception{
System.out.println("------Client--------");
//1.创建一个客户端Socket对象,构造方法中绑定服务器的IP地址和端口号
Socket client = new Socket("localhost",8888);
//2. 客户端发送消息
BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
DataInputStream dis = new DataInputStream(client.getInputStream());
boolean isRunning = true;
while (isRunning){
String msg = console.readLine();
dos.writeUTF(msg);
//3.获取消息
msg = dis.readUTF();
System.out.println(msg);
}
dos.flush();
//释放资源
dos.close();
dis.close();
client.close();
}
}
存在问题:虽然实现了一个用户可以正常收发消息,但是服务器只能接入一个用户。
解决方法:采用While循环的方式,持续接收用户。
3. 第三版:实现一个服务器可以接受多个用户。
/**
* 在线聊天室:服务器
* 目标:实现多个客户可以正常收发多条信息 :外层加入while循环后可以一直的去获取其他用户的连接(实现了多个用户的使用)
*
* 问题:在当前的main线程中必须等待第一个接入的用户退出后才能接入第二个用户(虽然实现了多个用户的接入,
* 但是存在用户之前排队的问题)即没有使用多线程
*/
public class MultiChat {
public static void main(String[] args) throws Exception{
System.out.println("----------Server------------");
//1.指定端口 使用ServerSocket创建服务器
ServerSocket server = new ServerSocket(8888);
//2.阻塞式等待连接accept
while (true){
Socket client = server.accept();
DataInputStream dis = new DataInputStream(client.getInputStream());
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
System.out.println("一个客户建立了连接");
boolean isRunning = true;
while (isRunning){
//3.接受消息
String msg = dis.readUTF();
//4.返回消息
dos.writeUTF(msg);
}
//释放资源
dos.flush();
dos.close();
dis.close();
server.close();
}
}
}
所存在问题:虽然实现了可以接受多个用户的接入,但是无法同时接入过个用户(即存在用户等待缺陷:必须让第一个用户关闭连接,下一个用户才能接入)
解决方法:让服务端每接入一个用户就开启一个线程(即采用多线程的方式)。
4. 第四版:实现一个服务器可以接受多个用户并且不存在用户排队问题。
/**
* 在线聊天室:服务器
* 目标:使用多线程实现多个客户可以正常收发多条信息
* 问题 1. 代码不好维护
* 2.客户端读写没有分开 必须先写后读
*/
public class ThreadMultiChat {
public static void main(String[] args) throws Exception{
System.out.println("----------Server------------");
//1.指定端口 使用ServerSocket创建服务器
ServerSocket server = new ServerSocket(8888);
//2.阻塞式等待连接accept
while (true){
Socket client = server.accept();
new Thread(new Runnable() {
@Override
public void run() {
DataInputStream dis = null;
DataOutputStream dos = null;
try {
dis = new DataInputStream(client.getInputStream());
dos = new DataOutputStream(client.getOutputStream());
System.out.println("一个客户建立了连接");
boolean isRunning = true;
while (isRunning){
//3.接受消息
String msg = dis.readUTF();
//4.返回消息
dos.writeUTF(msg);
}
dos.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
//释放资源
try {
if (dos != null) {
dos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (dis != null) {
dis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}
//server.close();服务器不用关闭了
}
}
存在问题:虽然解决了用户排队问题,但是服务端代码不好维护,代码没有封装。
解决方法:对服务端代码进行封装。
5. 第五版:对服务端代码进行封装
/**
* 在线聊天室:服务器
* 目标:使用静态内部类的方式对“多线程实现多个客户可以正常收发多条信息”进行封装
*/
public class ThreadMultiChat {
public static void main(String[] args) throws Exception{
System.out.println("----------Server------------");
//1.指定端口 使用ServerSocket创建服务器
ServerSocket server = new ServerSocket(8888);
//2.阻塞式等待连接accept
while (true){
Socket client = server.accept();
System.out.println("一个客户端建立了连接");
new Thread(new Channel(client)).start();
}
//server.close();服务器不用关闭了
}
//一个客户一个Channel
static class Channel implements Runnable{
private DataInputStream dis;
private DataOutputStream dos;
private Socket client;
private boolean isRunning;
public Channel(Socket client) {
this.client = client;
try {
dis = new DataInputStream(client.getInputStream());
dos = new DataOutputStream(client.getOutputStream());
isRunning = true;
} catch (IOException e) {
//e.printStackTrace();
//如果这里出现了异常,直接退出释放资源
System.out.println("构造方法出问题");
release();
}
}
//接受消息
private String receive(){
String msg = "";
try {
msg= dis.readUTF();
} catch (IOException e) {
//如果这里出现了异常,直接退出释放资源
System.out.println("接受消息出问题");
release();
}
return msg;
}
//发送消息
private void send(String msg){
//4.返回消息
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
//e.printStackTrace();
//如果这里出现了异常,直接退出释放资源
System.out.println("发送消息出问题了");
release();
}
}
//释放资源
private void release(){
this.isRunning = false;
Utils.close(dis,dos,client);
}
@Override
public void run() {
while (isRunning){
String msg = receive();
//当我们读取到的消息不为空时我们才回复消息,避免空指针异常
if (!msg.equals("")){
send(msg);
}
}
}
}
}
/**
* 工具类
* 用与释放资源
*/
public class Utils {
public static void close(Closeable... targets) {
for (Closeable target:targets) {
try {
if (null != target ) {
target.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
存在问题:虽然对服务端代码进行了封装,但是客户端代码没有进行封装,按照oop原则来说,客户端存在读和写两种状态,因此,应该对客户端进行读写分离。
解决方法:对客户端代码分别创建两个工具类,一个接受信息的类Receive,一个发送信息的类Send。
思考:为什么要对读和写两个类进行多线程改造??
- 读和写虽然分离了,但我们在创建一个客户端时,总不能够必须让读完才能写,或者是写完才能读。即必须同时进行。
- 当我们创建多个用户时,如果不采用多线程的形式,那么在创建用户的类中就存在了等待的状态,因此必须使用多线程。
6. 第六版:对客户端代码进行读写分离并封装。
发送端
/**思考:1.如果我们想创建多个用户进行发送时:总不能重写多个用户
* 2.为什么用户需要继承Runnable接口呢??
* 因为当我们在一个类中创建多个用户时,如果这个用户不是线程类的话我们就会陷入线程等待环节,
* 虽然我们可以直接使用匿名内部类的形式创建,但是我们需要重写了太对的run方法,所以要继承Runnable接口
*
* 使用多线程分装了发送端
*/
public class Send implements Runnable{
private BufferedReader console;
private DataOutputStream dos;
private Socket client;
private boolean isRunning;
//构造方法
public Send(Socket client) {
this.client = client;
console = new BufferedReader(new InputStreamReader(System.in));
try {
dos = new DataOutputStream(client.getOutputStream());
isRunning = true;
} catch (IOException e) {
//e.printStackTrace();
System.out.println("客户端构造方法出现问题");
release();
}
}
@Override
public void run() {
while (isRunning){
//发送端
String msg = getStrFromConsole();
if (!msg.equals("")) {
send(msg);
}
}
}
//发送消息
private void send(String msg){
try {
dos.writeUTF(msg);
} catch (IOException e) {
System.out.println("发送端出现问题");
release();
}
}
//从控制台获取消息
private String getStrFromConsole(){
try {
return console.readLine();
} catch (IOException e) {
e.printStackTrace();
System.out.println("读取消息出现问题");
release();
}
return "";
}
//释放资源
private void release(){
this.isRunning = false;
Utils.close(dos,client);
}
}
接收端
public class Receive implements Runnable{
private DataInputStream dis;
Socket client;
private boolean isRunning;
public Receive(Socket client) {
this.client = client;
try {
dis = new DataInputStream(client.getInputStream());
isRunning = true;
} catch (IOException e) {
System.out.println("构造方法出问题");
release();
}
}
@Override
public void run() {
while (isRunning){
String msg = receive();
if (!msg.equals("")) {
System.out.println(msg);
}
}
}
//接收消息
private String receive(){
String msg = "";
try {
msg = dis.readUTF();
return msg;
} catch (IOException e) {
System.out.println("接收消息出现问题");
release();
}
return "";
}
//释放资源
private void release(){
this.isRunning = false;
Utils.close(dis,client);
}
}
客户端
public class ThreadMultiClient {
public static void main(String[] args) throws Exception{
System.out.println("------Client--------");
//1.创建一个客户端Socket对象,构造方法中绑定服务器的IP地址和端口号
Socket client = new Socket("localhost",8888);
//2. 一个客户端有接收端和发送端两个端口
//发送端
new Thread(new Send(client)).start();
//接收端
new Thread(new Receive(client)).start();
}
}
存在问题:虽然解决了一系列问题,但是我们并没有实现群聊,只能够让一个用户进行读写,其他用户读取不到另一个用户所发送的消息。
解决方法:在服务端中,利用容器的方式,将接入的用户全存放在容器当中,当用户A向服务端发送消息时,我们利用容器获取到用户B,然后将用户A发送给服务器的消息转发给用户B。
6. 第七版:实现群聊。
- 客户端发送消息端口
public class Send implements Runnable{
private BufferedReader console;
private DataOutputStream dos;
private Socket client;
private boolean isRunning;
private String name;
//构造方法
public Send(Socket client,String name) {
this.name = name;
this.client = client;
console = new BufferedReader(new InputStreamReader(System.in));
try {
dos = new DataOutputStream(client.getOutputStream());
send(name);
isRunning = true;
} catch (IOException e) {
//e.printStackTrace();
System.out.println("客户端构造方法出现问题");
release();
}
}
@Override
public void run() {
while (isRunning){
//发送端
String msg = getStrFromConsole();
if (!msg.equals("")) {
send(msg);
}
}
}
//发送消息
private void send(String msg){
try {
dos.writeUTF(msg);
} catch (IOException e) {
System.out.println("发送端出现问题");
release();
}
}
//从控制台获取消息
private String getStrFromConsole(){
try {
return console.readLine();
} catch (IOException e) {
e.printStackTrace();
System.out.println("读取消息出现问题");
release();
}
return "";
}
//释放资源
private void release(){
this.isRunning = false;
Utils.close(dos,client);
}
}
- 客户端接收消息端口
public class Receive implements Runnable{
private DataInputStream dis;
Socket client;
private boolean isRunning;
public Receive(Socket client) {
this.client = client;
try {
dis = new DataInputStream(client.getInputStream());
isRunning = true;
} catch (IOException e) {
System.out.println("构造方法出问题");
release();
}
}
@Override
public void run() {
while (isRunning){
String msg = receive();
if (!msg.equals("")) {
System.out.println(msg);
}
}
}
//接收消息
private String receive(){
String msg = "";
try {
msg = dis.readUTF();
return msg;
} catch (IOException e) {
System.out.println("接收消息出现问题");
release();
}
return "";
}
//释放资源
private void release(){
this.isRunning = false;
Utils.close(dis,client);
}
}
- 服务器端
public class Chat {
private static CopyOnWriteArrayList<Channel> all = new CopyOnWriteArrayList<>();
public static void main(String[] args) throws Exception{
System.out.println("----------Server------------");
//1.指定端口 使用ServerSocket创建服务器
ServerSocket server = new ServerSocket(8888);
//2.阻塞式等待连接accept
while (true){
Socket client = server.accept();
System.out.println("一个客户端建立了连接");
Channel c = new Channel(client);
all.add(c);//将所有的客户端加入到容器里面,管理所有的客户端
new Thread(c).start();
}
}
//一个客户一个Channel
static class Channel implements Runnable{
private DataInputStream dis;
private DataOutputStream dos;
private Socket client;
private boolean isRunning;
private String name;
public Channel(Socket client) {
this.client = client;
try {
dis = new DataInputStream(client.getInputStream());
dos = new DataOutputStream(client.getOutputStream());
isRunning = true;
//获取名称
this.name = receive();
//欢迎你的到来
this.send("欢迎你的到来");
sendOthers(this.name + "来了聊天室",true);
} catch (IOException e) {
//e.printStackTrace();
//如果这里出现了异常,直接退出释放资源
System.out.println("构造方法出问题");
release();
}
}
//接受消息
private String receive(){
String msg = "";
try {
msg= dis.readUTF();
} catch (IOException e) {
//如果这里出现了异常,直接退出释放资源
System.out.println("接受消息出问题");
release();
}
return msg;
}
//发送消息
private void send(String msg){
//4.返回消息
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
//e.printStackTrace();
//如果这里出现了异常,直接退出释放资源
System.out.println("发送消息出问题了");
release();
}
}
/**
* 获取自己的消息,发给其他人
* @param msg
* 私聊:数据格式为:@xxx:msg
*/
private void sendOthers(String msg,boolean isSys) {
boolean isPrivate = msg.startsWith("@");
if (isPrivate) {//私聊
int idx = msg.indexOf(":");
//获取目标和数据
String targetName = msg.substring(1, idx);
msg = msg.substring(idx + 1);
for (Channel other : all) {
if (other.name.equals(targetName)) {
other.send(this.name + "悄悄对您说:" + msg);
}
}
} else {
for (Channel other : all) {
if (other == this) {
continue;
}
if (!isSys) {
other.send(this.name + "对所有人说:" + msg);
} else {
other.send(msg);//系统消息
}
}
}
}
//释放资源
private void release(){
this.isRunning = false;
Utils.close(dis,dos,client);
//退出
all.remove(this);
sendOthers(this.name + "离开了大家庭。。。。",true);
}
@Override
public void run() {
while (isRunning){
String msg = receive();
//当我们读取到的消息不为空时我们才回复消息,避免空指针异常
if (!msg.equals("")){
sendOthers(msg,false);
}
}
}
}
}
- 客户端
public class Client {
public static void main(String[] args) throws Exception{
System.out.println("------Client--------");
//1.创建一个客户端Socket对象,构造方法中绑定服务器的IP地址和端口号
Socket client = new Socket("localhost",8888);
//2. 一个客户端有接收端和发送端两个端口
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入用户名");
String name = br.readLine();
//发送端
new Thread(new Send(client,name)).start();
//接收端
new Thread(new Receive(client)).start();
}
}
- 工具类
public class Utils {
public static void close(Closeable... targets) {
for (Closeable target:targets) {
try {
if (null != target ) {
target.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}