文章目录
- 第16章_网络编程拓展练习
- TCP编程
- 1、学生与老师交互
- 2、查询单词
- 3、拓展:查询单词
- 4、图片上传
- 5、拓展:图片上传
- 6、多个客户端上传文件
- 7、群聊
- UDP编程
- 8、群发消息
第16章_网络编程拓展练习
TCP编程
1、学生与老师交互
案例:客户端模拟学生咨询,服务器端模拟咨询老师,进行交互。
客户端收到信息:
欢迎咨询尚硅谷!
这个月的所有期班都已经满了,只能报下一个月的了!
服务器端收到信息:
你好,我想报名这个月的JavaEE就业班!
好的,赶紧给我占个座!
提示:
(1)如果是一个客户端与服务器端交互,怎么实现
(2)如果是多个客户端与服务器交互,怎么实现
package com.atguigu.exercise1;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;public class Exercise1Client {public static void main(String[] args) {Socket socket = null; // 创建Socket指定ip地址和端口号PrintStream ps = null;try {socket = new Socket("127.0.0.1", 8888);// 获取输入流BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));System.out.println(br.readLine());// 获取输出流ps = new PrintStream(socket.getOutputStream());ps.println("你好,我想报名这个月的JavaEE就业班!");System.out.println(br.readLine());ps.println("好的,赶紧给我占个座!");} catch (IOException e) {e.printStackTrace();} finally {if (ps != null)ps.close();if (socket != null) {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}
}
(1)服务端接收1个客户端访问
package com.atguigu.exercise1;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.time.LocalDateTime;public class Exercise1Server {public static void main(String[] args) {ServerSocket server = null;Socket socket = null;try {server = new ServerSocket(8888);socket = server.accept();// 获取输出流PrintStream ps = new PrintStream(socket.getOutputStream());ps.println("欢迎咨询尚硅谷!");// 获取输入流BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));System.out.println(socket.getInetAddress().getHostAddress() + "留言:" + LocalDateTime.now());System.out.println(br.readLine() + "\n");ps.println("这个月的所有期班都已经满了,只能报下一个月的了!");System.out.println(socket.getInetAddress().getHostAddress() + "留言:" + LocalDateTime.now());System.out.println(br.readLine());} catch (IOException e) {e.printStackTrace();} finally {try {if (socket != null)socket.close();} catch (IOException e) {e.printStackTrace();}try {if (server != null)server.close();} catch (IOException e) {e.printStackTrace();}}}
}
(2)服务端接收多个客户端访问
package com.atguigu.exercise1;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.time.LocalDateTime;public class Exercise1 {public static void main(String[] args) {ServerSocket server = null;try {server = new ServerSocket(8888);boolean flag = true;while (flag) {Socket socket = server.accept();new Thread() {public void run() {try {// 获取输出流PrintStream ps = new PrintStream(socket.getOutputStream());ps.println("欢迎咨询尚硅谷");// 获取输入流BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));System.out.println(socket.getInetAddress().getHostAddress() + "留言:" + LocalDateTime.now());System.out.println(br.readLine() + "\n");ps.println("这个月的所有期班都已经满了,只能报下一个月的了!");System.out.println(socket.getInetAddress().getHostAddress() + "留言:" + LocalDateTime.now());System.out.println(br.readLine());socket.close();} catch (IOException e) {e.printStackTrace();}}}.start();}} catch (IOException e) {e.printStackTrace();} finally {try {if (server != null)server.close();} catch (IOException e) {e.printStackTrace();}}}
}
2、查询单词
案例:模拟客户端输入要查询的中文,服务器返回对应的英文单词
效果如下:
开发提示:
(1)服务器端有一个map,key是中文词语,value是对应的单词
(2)服务器接收到客户端的词语后,从map中get,如果可以找到,就返回单词,如果找不到,就返回“没有找到”
package com.atguigu.exercise2;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;public class Exercise2Server {public static void main(String[] args) {ServerSocket server = null;Socket socket = null;try {HashMap<String, String> dictionary = new HashMap<String, String>();dictionary.put("星期一", "Monday");dictionary.put("星期二", "Tuesday");dictionary.put("星期三", "Wednesday");dictionary.put("星期四", "Thursday");dictionary.put("星期五", "Friday");dictionary.put("星期六", "Saturday");dictionary.put("星期七", "Sunday");//...server = new ServerSocket(8888);socket = server.accept();// 获取输入流BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));// 获取输出流PrintStream ps = new PrintStream(socket.getOutputStream());//接收客户端的中文String key = br.readLine();//查询对应的英文单词,并返回结果String words = dictionary.get(key);if (words != null) {ps.println(words);} else {ps.println("o(╥﹏╥)o没有找到对应的单词!");}} catch (IOException e) {e.printStackTrace();} finally {try {if (socket != null)socket.close();} catch (IOException e) {e.printStackTrace();}try {if (server != null)server.close();} catch (IOException e) {e.printStackTrace();}}}
}
package com.atguigu.exercise2;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;public class Exercise2Client {public static void main(String[] args) {Socket socket = null;Scanner input = null;try {// 创建Socket指定ip地址和端口号socket = new Socket("127.0.0.1", 8888);input = new Scanner(System.in);System.out.print("请输入要查询的词语:");String content = input.next();// 获取输出流PrintStream ps = new PrintStream(socket.getOutputStream());ps.println(content);// 获取输入流BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));System.out.println("查询结果:" + br.readLine());} catch (IOException e) {e.printStackTrace();} finally {try {if (socket != null)socket.close();} catch (IOException e) {e.printStackTrace();}if (input != null)input.close();}}
}
3、拓展:查询单词
修改前一个题目,改为并发版。
服务器端:
package com.atguigu.exercise3;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;public class Exercise3Server {private static HashMap<String, String> dictionary = new HashMap<String, String>();static {dictionary.put("星期一", "Monday");dictionary.put("星期二", "Tuesday");dictionary.put("星期三", "Wednesday");dictionary.put("星期四", "Thursday");dictionary.put("星期五", "Friday");dictionary.put("星期六", "Saturday");dictionary.put("星期七", "Sunday");}public static void main(String[] args) {ServerSocket server = null;try {server = new ServerSocket(8888);while (true) {Socket socket = server.accept();new QueryThread(socket).start();}} catch (IOException e) {e.printStackTrace();} finally {try {if (server != null)server.close();} catch (IOException e) {e.printStackTrace();}}}private static class QueryThread extends Thread {Socket socket;public QueryThread(Socket socket) {this.socket = socket;}@Overridepublic void run() {BufferedReader br = null;PrintStream ps = null;try {// 获取输入流br = new BufferedReader(new InputStreamReader(socket.getInputStream()));// 获取输出流ps = new PrintStream(socket.getOutputStream());//接收客户端的中文String key = br.readLine();//查询对应的英文单词,并返回结果String words = dictionary.get(key);if (words != null) {ps.println(words);} else {ps.println("o(╥﹏╥)o没有找到对应的单词!");}} catch (IOException e) {e.printStackTrace();;} finally {try {if (br != null)br.close();} catch (IOException e) {e.printStackTrace();}if (ps != null)ps.close();try {if (socket != null)socket.close();} catch (IOException e) {e.printStackTrace();}}}}
}
客户端:
package com.atguigu.exercise3;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;public class Exercise3Client {public static void main(String[] args) {Socket socket = null;Scanner input = null;PrintStream ps = null;BufferedReader br = null;try {// 创建Socket指定ip地址和端口号socket = new Socket("127.0.0.1", 8888);input = new Scanner(System.in);System.out.print("请输入要查询的词语:");String content = input.next();// 获取输出流ps = new PrintStream(socket.getOutputStream());ps.println(content);// 获取输入流br = new BufferedReader(new InputStreamReader(socket.getInputStream()));System.out.println("查询结果:" + br.readLine());} catch (IOException e) {e.printStackTrace();} finally {if (ps != null)ps.close();try {if (br != null)br.close();} catch (IOException e) {e.printStackTrace();}try {if (socket != null)socket.close();} catch (IOException e) {e.printStackTrace();}if (input != null)input.close();}}
}
4、图片上传
案例:客户端给服务器端上传照片
要求:
(1)客户端上传的照片,需要是jpg格式的,并且大小在2M(含)以内的,否则不能上传
(2)要求上传成功后,服务器要返回上传成功,如果上传失败,服务器返回上传失败
(3)客户端上传到服务器端的照片,存储在项目名下"photo"的文件夹中,并且以“照片原文件名+时间戳.jpg”命名
效果如下:
package com.atguigu.exercise4;import java.io.DataInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;public class Exercise4Server{public static void main(String[] args) {ServerSocket server = null;Socket socket = null;DataInputStream dis = null;PrintStream ps = null;FileOutputStream fos = null;try {//开启服务器server = new ServerSocket(8888);//接收一个客户端的连接socket = server.accept();//获取输入流dis = new DataInputStream(socket.getInputStream());//获取输出流ps = new PrintStream(socket.getOutputStream());//(1)先读取文件名String filename = dis.readUTF();//(2)生成唯一的文件名String destfile = "photo" + "/" + filename + System.currentTimeMillis() + ".jpg";//(3)读取文件内容,并写入目标文件fos = new FileOutputStream(destfile);try {byte[] data = new byte[1024];int len;while ((len = dis.read(data)) != -1) {fos.write(data, 0, len);}//返回结果给客户端ps.println("接收成功!");} catch (Exception e) {//返回结果给客户端ps.println("接收失败!");}} catch (IOException e) {e.printStackTrace();} finally {try {if (fos != null)fos.close();} catch (IOException e) {e.printStackTrace();}ps.close();try {if (dis != null)dis.close();} catch (IOException e) {e.printStackTrace();}try {if (socket != null)socket.close();} catch (IOException e) {e.printStackTrace();}try {if (server != null)server.close();} catch (IOException e) {e.printStackTrace();}}}
}
package com.atguigu.exercise4;import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.Scanner;public class Exercise4Client {public static void main(String[] args)throws IOException {//连接服务器Socket socket= new Socket("127.0.0.1",8888);//选择要上传的文件Scanner input = new Scanner(System.in);System.out.println("请选择要上传的文件:");//例如:D:\尚硅谷_0325班_柴林燕_JavaSE\笔记\第14章 IO流.docxString fileStr = input.nextLine();File file = new File(fileStr);if(!fileStr.endsWith(".jpg")){System.out.println("照片必须是.jpg格式");input.close();socket.close();return;}if(file.length()>1024*1024*2){System.out.println("照片必须在2M(含)以内");input.close();socket.close();return;}DataOutputStream dos = null;//从file读取内容,给服务器发送FileInputStream fis = null;try {//获取输出流dos = new DataOutputStream(socket.getOutputStream());//先发送文件名dos.writeUTF(file.getName().substring(0, file.getName().lastIndexOf(".")));//发送文件内容fis = new FileInputStream(file);byte[] data = new byte[1024];int len;while((len = fis.read(data)) !=-1){dos.write(data, 0, len);}socket.shutdownOutput();//告诉服务器,我发送完毕} catch (Exception e) {System.out.println("上传失败");}finally{fis.close();dos.close();}//接收结果BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String result = br.readLine();System.out.println(result);br.close();socket.close();input.close();}}
5、拓展:图片上传
相较于上题,修改为并发版。
服务器端:
package com.atguigu.exercise5;import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;public class Exercise5Server {public static void main(String[] args) {ServerSocket server = null;try {//开启服务器server = new ServerSocket(8888);while (true) {//接收一个客户端的连接Socket socket = server.accept();new UploadPhotoThread(socket).start();}} catch (IOException e) {e.printStackTrace();} finally {try {if (server != null)server.close();} catch (IOException e) {e.printStackTrace();}}}private static class UploadPhotoThread extends Thread {Socket socket;public UploadPhotoThread(Socket socket) {this.socket = socket;}@Overridepublic void run() {try (//获取输入流ObjectInputStream dis = new ObjectInputStream(socket.getInputStream());//获取输出流PrintStream ps = new PrintStream(socket.getOutputStream());){//(1)先读取文件名String filename = dis.readUTF();//(2)生成唯一的文件名String destfile = "photo" + "/" + filename + System.currentTimeMillis() + ".jpg";//(3)读取文件内容,并写入目标文件FileOutputStream fos = null;try {fos = new FileOutputStream(destfile);byte[] data = new byte[1024];int len;while ((len = dis.read(data)) != -1) {fos.write(data, 0, len);}//返回结果给客户端ps.println("接收成功!");} catch (Exception e) {//返回结果给客户端ps.println("接收失败!");} finally {fos.close();}} catch (IOException e) {e.printStackTrace();} finally {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}
}
客户端:
package com.atguigu.exercise5;import java.io.*;
import java.net.Socket;
import java.util.Scanner;public class Exercise5Client {public static void main(String[] args) throws IOException {//连接服务器Socket socket = new Socket("127.0.0.1", 8888);//选择要上传的文件Scanner input = new Scanner(System.in);System.out.println("请选择要上传的文件:");//例如:D:\尚硅谷_0325班_柴林燕_JavaSE\笔记\第14章 IO流.docxString fileStr = input.nextLine();File file = new File(fileStr);if (!fileStr.endsWith(".jpg")) {System.out.println("照片必须是.jpg格式");input.close();socket.close();return;}if (file.length() > 1024 * 1024 * 2) {System.out.println("照片必须在2M(含)以内");input.close();socket.close();return;}//获取输出流ObjectOutputStream dos = new ObjectOutputStream(socket.getOutputStream());//先发送文件名dos.writeUTF(file.getName().substring(0, file.getName().lastIndexOf(".")));//从file读取内容,给服务器发送FileInputStream fis = new FileInputStream(file);//发送文件内容byte[] data = new byte[1024];int len;while ((len = fis.read(data)) != -1) {dos.write(data, 0, len);}socket.shutdownOutput();//告诉服务器,我发送完毕//接收结果BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));String result = br.readLine();System.out.println(result);fis.close();dos.close();br.close();socket.close();input.close();}}
6、多个客户端上传文件
需求:每一个客户端启动后都可以给服务器上传一个文件;服务器接收到文件后保存到一个upload目录中,可以同时接收多个客户端的文件上传。
思考分析:
(1)服务器端要“同时”处理多个客户端的请求,那么必须使用多线程,每一个客户端的通信需要单独的线程来处理。
(2)服务器保存上传文件的目录只有一个upload,而每个客户端给服务器发送的文件可能重名,所以需要保证文件名的唯一。我们可以使用“时间戳”作为文件名,而后缀名不变
(3)客户端需要给服务器上传文件名(含后缀名)以及文件内容。而文件名是字符串,文件内容不一定是纯文本的,因此选择ObjectOutputStream 和 ObjectInputStream。
服务器示例代码:
package com.atguigu.exercise6;import java.net.ServerSocket;
import java.net.Socket;public class Exercise6Server {public static void main(String[] args) {ServerSocket server = null;try {//服务器在8888端口号监听数据server = new ServerSocket(8888);while (true) {//(2)等待连接//这句代码执行一次,意味着一个客户端连接Socket accept = server.accept();FileUploadThread ft = new FileUploadThread(accept);ft.start();}} catch (IOException e) {e.printStackTrace();} finally {try {if (server != null)server.close();} catch (IOException e) {e.printStackTrace();}}}
}
package com.atguigu.exercise6;import java.io.*;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;public class FileUploadThread extends Thread {private Socket socket;private String dir = "upload/";//可以把它放到配置文件中public FileUploadThread(Socket socket) {this.socket = socket;}public void run() {FileOutputStream fos = null;ObjectInputStream dis = null;PrintStream ps = null;try {InputStream is = socket.getInputStream();dis = new ObjectInputStream(is);OutputStream out = socket.getOutputStream();ps = new PrintStream(out);//读取文件名(含后缀名)String filename = dis.readUTF();int lastIndexOfDot = filename.lastIndexOf(".");//截取后缀名String ext = filename.substring(lastIndexOfDot);//生成时间戳SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmssSSS");//拼接新文件名 = 旧文件名 + 时间戳 + 后缀名String newFilename = filename.substring(0, lastIndexOfDot) + sf.format(new Date()) + ext;//拼接文件路径String pathname = dir + File.separator + newFilename;//用新文件路径构建文件输出流fos = new FileOutputStream(pathname);//接收文件内容byte[] data = new byte[1024];long sum = 0;int len;while ((len = dis.read(data)) != -1) {fos.write(data, 0, len);fos.flush();sum += len;}System.out.println("sum = " + sum);//返回结果ps.println(filename + "已上传完毕");} catch (Exception e) {e.printStackTrace();} finally {try {fos.close();} catch (IOException e) {e.printStackTrace();}try {if (dis != null)dis.close();} catch (IOException e) {e.printStackTrace();}if (ps != null)ps.close();try {socket.close();} catch (IOException e) {e.printStackTrace();}}}
}
客户端示例代码:
package com.atguigu.exercise6;import java.io.*;
import java.net.Socket;
import java.util.Scanner;public class Exercise6Client {public static void main(String[] args) {// (1)连接服务器Socket socket = null;FileInputStream fis = null;ObjectOutputStream dos = null;OutputStream out = null;Scanner input = null;BufferedReader br = null;try {socket = new Socket("127.0.0.1", 8888);input = new Scanner(System.in);out = socket.getOutputStream();// 用它的目的是为了既可以单独传一个字符串,又可以写字节内容dos = new ObjectOutputStream(out);InputStream is = socket.getInputStream();InputStreamReader isr = new InputStreamReader(is);// 把字节流转成字符流br = new BufferedReader(isr);// (2)从键盘输入文件的路径和名称System.out.print("请选择要上传的文件:");String path = input.nextLine();File file = new File(path);// 先发送文件名(含后缀名)dos.writeUTF(file.getName());// 单独发一个字符串// 还需要一个IO流,从文件读取内容,给服务器发过去fis = new FileInputStream(file);// (3)把文件内容给服务器传过去,类似与复制文件byte[] data = new byte[1024];int len;long sum = 0;while ((len = fis.read(data)) != -1) {dos.write(data, 0, len);sum += len;dos.flush();}System.out.println("sum = " + sum);socket.shutdownOutput();//数据发送完毕,不再发送,但是还要接收,所以是半关闭// (4)接收服务器返回的结果String result = br.readLine();System.out.println(result);} catch (Exception e) {e.printStackTrace();} finally {// (5)关闭try {if (fis != null)fis.close();} catch (IOException e) {e.printStackTrace();}try {if (dos != null)dos.close();} catch (IOException e) {e.printStackTrace();}try {if (out != null)out.close();} catch (IOException e) {e.printStackTrace();}if (input != null)input.close();try {if (br != null)br.close();} catch (IOException e) {e.printStackTrace();}try {if (socket != null)socket.close();} catch (IOException e) {e.printStackTrace();}}}
}
7、群聊
需求:客户端与服务器连接成功后,就可以看到其他客户端的发送的聊天信息,当前客户端也可以发送自己的聊天信息。
思考分析:
(1)服务器
要同时接收多个客户端的连接,因此需要多线程
服务器这边充当转发角色,即在服务器这边的某个客户端的Socket接收到自己客户端发送的消息后,要通过服务器端这边其他客户端的Socket将信息转发出去
(2)客户端
同时能够接收和发送消息,因此也要两个线程,一个接收,一个发送
服务器端示例代码:
package com.atguigu.exercise7;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Iterator;public class Exercise7Server {private static ArrayList<Socket> online = new ArrayList<Socket>();public static void main(String[] args) {ServerSocket server = null;try {//1、开启服务器server = new ServerSocket(9999);while (true) {//2、接收客户端的连接Socket socket = server.accept();//把这个客户端加入到online中online.add(socket);//每一个客户端独立的线程MessageHandler mh = new MessageHandler(socket);mh.start();}} catch (IOException e) {e.printStackTrace();} finally {try {if (server != null)server.close();} catch (IOException e) {e.printStackTrace();}}}private static class MessageHandler extends Thread {private Socket socket;private String ip;public MessageHandler(Socket socket) {super();this.socket = socket;this.ip = socket.getInetAddress().getHostAddress();}public void run() {BufferedReader br = null;PrintStream ps = null;try {//接收当前的客户端发送的消息InputStream in = socket.getInputStream();InputStreamReader isr = new InputStreamReader(in);br = new BufferedReader(isr);//这个客户端的一连接成功,线程一启动,就可以告诉其他人我上线了sendToOthers(ip + "上线了");while (true) {String content = br.readLine();if (content == null) {break;}//收到一句,转发一句sendToOthers(ip + "说:" + content);if ("bye".equals(content)) {//给自己发一句byeOutputStream out = socket.getOutputStream();ps = new PrintStream(out);ps.println("bye");break;}}sendToOthers(ip + "下线了");} catch (IOException e) {sendToOthers(ip + "掉线了");} finally {try {if (socket != null)socket.close();} catch (IOException e) {e.printStackTrace();}try {if (br != null)br.close();} catch (IOException e) {e.printStackTrace();}if (ps != null)ps.close();}}//因为转发的代码也很长,独立为一个方法public void sendToOthers(String str) {//遍历所有online的客户端Iterator<Socket> iterator = online.iterator();while (iterator.hasNext()) {Socket on = iterator.next();if (!on.equals(socket)) {//只给其他客户端转发try {OutputStream out = on.getOutputStream();PrintStream ps = new PrintStream(out);//不能用try(){}catch,因为这里不能关闭流和其他socketps.println(str);} catch (IOException e) {//说明on这个客户端要么下线了,要么掉线了iterator.remove();}}}}}
}
客户端示例代码:
package com.atguigu.exercise7;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;public class Exercise7Client {public static void main(String[] args) {Socket socket = null;try {// 1、连接服务器socket = new Socket("127.0.0.1", 9999);// 2、开启两个线程,一个收消息,一个发消息SendThread st = new SendThread(socket);ReceiveThread rt = new ReceiveThread(socket);st.start();rt.start();// 等发送线程停下来再往下走st.join();rt.interrupt();} catch (IOException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();} finally {//关闭sockettry {if (socket != null)socket.close();} catch (IOException e) {e.printStackTrace();}}}static class SendThread extends Thread {private Socket socket;public SendThread(Socket socket) {super();this.socket = socket;}public void run() {Scanner input = null;PrintStream ps = null;try {// 键盘输入input = new Scanner(System.in);OutputStream out = socket.getOutputStream();ps = new PrintStream(out);while (true) {// 从键盘输入System.out.print("请输入要发送的消息:");String content = input.nextLine();// 给服务器发送ps.println(content);// 如果bye,就结束发送if ("bye".equals(content)) {break;}}} catch (IOException e) {e.printStackTrace();} finally {if (input != null)input.close();if (ps != null)ps.close();}}}static class ReceiveThread extends Thread {private Socket socket;public ReceiveThread(Socket socket) {super();this.socket = socket;}public void run() {BufferedReader br = null;try {InputStream in = socket.getInputStream();InputStreamReader isr = new InputStreamReader(in);br = new BufferedReader(isr);while (true) {String line = br.readLine();if ("bye".equals(line)) {break;}System.out.println(line);}} catch (SocketException e) {System.out.println("退出");} catch (IOException e) {e.printStackTrace();} finally {if (br != null) {try {br.close();} catch (IOException e) {e.printStackTrace();}}}}}
}
UDP编程
8、群发消息
案例:模拟给全部同学群发“欢迎来到尚硅谷”
开发提示:使用UDP群发
package com.atguigu.exercise8;import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;public class Exercise8Send {public static void main(String[] args) {DatagramSocket ds = null;try {//(1)先建立一个DatagramSocketds = new DatagramSocket();//(2)准备发送的数据String str = "欢迎来到尚硅谷";byte[] data = str.getBytes();for (int i = 0; i <= 255; i++) {//(3)把数据包装成一个数据报//DatagramPacket(byte[] buf, int length, InetAddress address, int port)/** 第一个参数:要发送的数据的字节数组* 第二个参数:数组的长度* 第三个参数:接收方的IP地址* 第三个参数:接收方的端口号** 好比发快递,需要填写接收方的IP和端口号*/InetAddress ip = InetAddress.getByName("192.168.11." + i);int port = 8888;DatagramPacket dp = new DatagramPacket(data, data.length, ip, port);//(4)发送数据报// 通过socket发送ds.send(dp);}} catch (IOException e) {e.printStackTrace();} finally {//(5)断开if (ds != null)ds.close();}}
}
package com.atguigu.exercise8;import java.net.DatagramPacket;
import java.net.DatagramSocket;public class Exercise8Receiver {public static void main(String[] args) {DatagramSocket ds = null;try {//1、准备一个socket,用来接收消息//接收方,先确定端口号,监听数据的端口号//好比,要收到快递,需要先确定自己的地址和手机号,然后对方才能给你发ds = new DatagramSocket(8888);//2、准备一个数据报,来接收数据//DatagramPacket(byte[] buf, int length)byte[] data = new byte[1024 * 64];//64KDatagramPacket dp = new DatagramPacket(data, data.length);//3、接收数据ds.receive(dp);//4、拆包裹byte[] result = dp.getData();int len = dp.getLength();//实际接收的数据的长度System.out.println(new String(result, 0, len));} catch (IOException e) {e.printStackTrace();} finally {//5、关闭if (ds != null)ds.close();}}
}