黑马程序员---从头开始,回忆JAVA基础之通信(二)
来源:互联网 发布:无root修改手机mac地址 编辑:程序博客网 时间:2024/05/29 19:13
新春佳节不忘学习!
------------------------------------------------------------------------------------------------------------------------------------------------------
2. TCP通信
2.1. Socket通讯模型
1.1.1. Server端多线程模型
通过上一节我们已经知道了如何使用ServerSocket与Socket进行通讯了,但是这里存在着一个问题,就是只能“p2p”点对点。一个服务端对一个客户端。若我们想让一个服务端可以同时支持多个客户端应该怎么做呢?这时我们需要分析之前的代码。我们可以看到,当服务端的ServerSocket通过accept方法侦听到一个客户端Socket连接后,就获取该Socket并与该客户端通过流进行双方的通讯了,这里的问题在于,只有不断的调用accept方法,我们才能侦听到不同客户端的连接。但是若我们循环侦听客户端的连接,又无暇顾及与连接上的客户端交互,这时我们需要做的事情就是并发。我们可以创建一个线程类ClientHandler,并将于客户端交互的工作全部委托线程来处理。这样我们就可以在当一个客户端连接后,启动一个线程来负责与客户端交互,而我们也可以循环侦听客户端的连接了。
我们需要对服务端的代码进行修改:
1./**2. * Server端应用程序*3. */4.public class Server {5. public static void main(String[] args) {6. ServerSocket server = null;7. try {8. //创建ServerSocket并申请服务端口为80889. server = new ServerSocket(8088);10. 11. while(true){12. //循环侦听客户端的连接13. Socket socket = server.accept();14. //当一个客户端连接后,启动线程来处理该客户端的交互15. new ClientHandler(socket).start();16. }17. } catch (Exception e) {18. e.printStackTrace();19. } finally{20. if(server != null){21. try {22. server.close();23. } catch (IOException e) {24. }25. }26. }27. }28.}29./**30. * 线程类31. * 该线程的作用是并发与客户端进行交互32. * 这里的代码就是原来在Server中客户端连接后交互的代码33. */34.class ClientHandler extends Thread{35. private Socket socket;36. public ClientHandler(Socket socket){37. this.socket = socket;38. }39. public void run(){40. try {41. //获取输入流,用于读取客户端发送过来的消息42. InputStream in = socket.getInputStream();43. BufferedReader reader44. = new BufferedReader(45. new InputStreamReader(46. in,"UTF-8"47. )48. );49. 50. //获取输出流,用于向该客户端发送消息51. OutputStream out = socket.getOutputStream();52. PrintWriter writer53. = new PrintWriter(54. new OutputStreamWriter(55. out,"UTF-8" 56. ),true57. );58. 59. //读取客户端发送的消息60. String message = reader.readLine();61. System.out.println("客户端说:"+message);62. 63. //向客户端发送消息64. writer.println("你好客户端!");65. } catch (Exception e) {66. e.printStackTrace();67. }68. }69.}
经过上面的改动,我们再次启动服务端,这个时候我们会发现,我们启动若干客户端都可以被服务器所接受并进行交互了。
3. UDP通信
3.1. DatagramPacket
3.1.1. 创建接收包
DatagramPacket:UDP数据报基于IP建立的,每台主机有65536个端口号可以使用。数据报中字节数限制为65536-8 。包含8字节的头信息。
构造接收包:
DatagramPacket(byte[] buf, int length)
将数据包中Length长的数据装进Buf数组。
DatagramPacket(byte[] buf, int offset, int length)
将数据包中从Offset开始、Length长的数据装进Buf数组。
3.1.2. 创建发送包
构造发送包:
DatagramPacket(byte[] buf, int length, InetAddress clientAddress, int clientPort)
从Buf数组中,取出Length长的数据创建数据包对象,目标是clientAddress地址,clientPort端口,通常用来发送数据给客户端。
DatagramPacket(byte[] buf, int offset, int length, InetAddress clientAddress, int clientPort)
从Buf数组中,取出Offset开始的、Length长的数据创建数据包对象,目标是clientAddress地址,clientPort端口,通常用来发送数据给客户端。
3.2. DatagramSocket
3.2.1. 服务端接收
DatagramSocke用于接收和发送UDP的Socket实例 。
DatagramSocket(int port)
创建实例,并固定监听Port端口的报文。通常用于服务端。
其中方法:
receive(DatagramPacket d)
接收数据报文到d中。receive方法产生 “阻塞”。会一直等待知道有数据被读取到。
3.2.2. 客户端发送
无参的构造方法DatagramSocket()通常用于客户端编程,它并没有特定监听的端口,仅仅使用一个临时的。程序会让操作系统分配一个可用的端口。
其中方法:
send(DatagramPacket dp)
该方法用于发送报文dp到目的地。
代码如下:
1. /**2. * Server端程序3. */4. public class Server {5. public static void main(String[] args) {6. DatagramSocket socket = null;7. try {8. socket = new DatagramSocket(8088);//申请8088端口9. byte[] data = new byte[1024];10. DatagramPacket packet11. = new DatagramPacket(data, data.length);//创建接收包12. socket.receive(packet);//会产生阻塞,读取发送过来的数据13. String str = new String(packet.getData(),0,packet.getLength());//从包中取数据14. System.out.println(str);15. 16. } catch (Exception e) {17. e.printStackTrace();18. } finally{19. if(socket != null){20. socket.close();//关闭释放资源21. }22. }23. }24.}25./**26. * Client端程序27. */28.public class Client {29. public static void main(String[] args) {30. DatagramSocket socket = null;31. try {32. socket = new DatagramSocket();//创建Socket33. byte[] data = "你好服务器!".getBytes();34. DatagramPacket packet = new DatagramPacket(35. data, 36. data.length,37. InetAddress.getByName("localhost"),38. 808839. );//创建发送包40. socket.send(packet);//发送数据41. 42. 43. } catch (Exception e) {44. e.printStackTrace();45. } finally{46. if(socket != null){47. socket.close();//关闭以释放资源48. }49. }50. }51.}
- 黑马程序员---从头开始,回忆JAVA基础之通信(二)
- 黑马程序员---从头开始,回忆JAVA基础之通信(一)
- 黑马程序员---从头开始,回忆JAVA基础之集合(二)
- 黑马程序员---从头开始,回忆JAVA基础之IO流(二)
- 黑马程序员---从头开始,回忆JAVA基础之正则表达式。
- 黑马程序员---从头开始,回忆JAVA基础之Eclipse快捷键
- 黑马程序员---从头开始,回忆JAVA基础之常用词汇
- 黑马程序员---从头开始,回忆JAVA基础之文件操作
- 黑马程序员---从头开始,回忆JAVA基础之反射
- 黑马程序员---从头开始,回忆JAVA基础之代理
- 黑马程序员---从头开始,回忆JAVA基础之集合(一)
- 黑马程序员---从头开始,回忆JAVA基础之IO流(一)
- 黑马程序员---从头开始,回忆JAVA基础之JAVA用十六进制表示浮点数的方法
- 黑马程序员---从头开始,回忆JAVA基础之常用类方法!
- 黑马程序员-----java基础二(之java语法基础)
- 黑马程序员----Java基础(六):面向对象之二
- 黑马程序员——Java之编程基础(二)
- 从头开始学java--GUI(二)
- 读《大道至简-软件工程实践者的思想》
- 胜利大逃亡(续)(状态压缩+三维BFS)
- 内部类详解
- ES学习笔记2-理论进阶篇1
- linux 基础
- 黑马程序员---从头开始,回忆JAVA基础之通信(二)
- Linux 常用命令
- 算法入门->冒泡排序->C/C++ 语言实现
- CodeForces515B Drazil and His Happy Friends (数学)
- IBM Watson 服务在 Bluemix 中的应用
- linux 文件权限
- 姑外婆99岁了
- 英语学习网
- 提示:bash: groupadd: command not found