注:本文来自:简书:jianshu

作者:jijs
链接:http://www.jianshu.com/p/7c0722a8b66f
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

需要提前了解知识点
java.net.Socket 解析
java.net.ServerSocket 解析

使用socket实现一个端对端聊天系统。

消息的格式为:消息长度(int)+消息内容

通过消息长度来进行socket分包,防止读取出现半包、粘包等问题。

服务端代码

  1. 1 import java.io.IOException;
  2. 2 import java.io.InputStream;
  3. 3 import java.io.OutputStream;
  4. 4 import java.net.ServerSocket;
  5. 5 import java.net.Socket;
  6. 6
  7. 7 /**
  8. 8 * @author jijs
  9. 9 * @date 2017-08-14
  10. 10 */
  11. 11 public class ChatServer {
  12. 12 public static void main(String[] args) throws Exception {
  13. 13 start();
  14. 14 }
  15. 15
  16. 16 public static void start() throws Exception {
  17. 17 try (ServerSocket ss = new ServerSocket(9000);
  18. 18 Socket s = ss.accept();
  19. 19 InputStream is = s.getInputStream();
  20. 20 OutputStream os = s.getOutputStream();) {
  21. 21
  22. 22 //开启一个线程,实时读取对方发过来的消息
  23. 23 new Thread(ChatUtil.receive(is)).start();
  24. 24
  25. 25 //从控制台输入消息,并发送
  26. 26 ChatUtil.send(os);
  27. 27
  28. 28 } catch (IOException e) {
  29. 29 e.printStackTrace();
  30. 30 }
  31. 31
  32. 32 }
  33. 33
  34. 34 }

客户端代码

  1. 1 import java.io.IOException;
  2. 2 import java.io.InputStream;
  3. 3 import java.io.OutputStream;
  4. 4 import java.net.Socket;
  5. 5
  6. 6 /**
  7. 7 * @author jijs
  8. 8 * @date 2017-08-14
  9. 9 */
  10. 10 public class ChatClient {
  11. 11
  12. 12 public static void main(String[] args) throws Exception {
  13. 13 start();
  14. 14 }
  15. 15
  16. 16 public static void start() {
  17. 17 try (Socket s = new Socket("127.0.0.1", 9000);
  18. 18 InputStream is = s.getInputStream();
  19. 19 OutputStream os = s.getOutputStream();) {
  20. 20
  21. 21 //开启一个线程,实时读取对方发过来的消息
  22. 22 new Thread(ChatUtil.receive(is)).start();
  23. 23
  24. 24 //从控制台输入消息,并发送
  25. 25 ChatUtil.send(os);
  26. 26
  27. 27 } catch (IOException e) {
  28. 28 e.printStackTrace();
  29. 29 }
  30. 30
  31. 31 }
  32. 32
  33. 33 }

聊天工具类

  1. 1 import java.io.IOException;
  2. 2 import java.io.InputStream;
  3. 3 import java.io.OutputStream;
  4. 4 import java.util.Scanner;
  5. 5
  6. 6 /**
  7. 7 * @author jijs
  8. 8 * @date 2017-08-14
  9. 9 */
  10. 10 public class ChatUtil {
  11. 11
  12. 12 /**
  13. 13 * 读取对方发过来的消息
  14. 14 * @param is
  15. 15 * @return
  16. 16 */
  17. 17 public static Runnable receive(final InputStream is) {
  18. 18 return new Runnable() {
  19. 19 public void run() {
  20. 20 while (true) {
  21. 21 try {
  22. 22 // 当前消息总字节长度
  23. 23 int returnLen = ChatUtil.readLen(is);
  24. 24 byte[] b = new byte[returnLen];
  25. 25 int readSize = 0; // 每次读取的字节数
  26. 26 int count = 0; // 总读取的字节数
  27. 27 while (count < returnLen && (readSize = is.read(b)) != -1) {
  28. 28 count += readSize;
  29. 29 }
  30. 30 String str = new String(b, 0, readSize);
  31. 31 System.out.println("接收:" + str);
  32. 32 } catch (IOException e) {
  33. 33 e.printStackTrace();
  34. 34 break;
  35. 35 }
  36. 36 }
  37. 37 }
  38. 38 };
  39. 39 }
  40. 40
  41. 41 /**
  42. 42 * 从控制台接收用户输入,发送消息给对方
  43. 43 * @param os
  44. 44 */
  45. 45 public static void send(final OutputStream os) {
  46. 46 Scanner scan = new Scanner(System.in);
  47. 47 while (true) {
  48. 48 try {
  49. 49 String s = scan.nextLine();
  50. 50 byte[] data = s.getBytes();
  51. 51 int len = data.length;
  52. 52 os.write(ChatUtil.int2byte(len));
  53. 53 os.write(data);
  54. 54 os.flush();
  55. 55 } catch (IOException e) {
  56. 56 e.printStackTrace();
  57. 57 break;
  58. 58 }
  59. 59 }
  60. 60 scan.close();
  61. 61 }
  62. 62
  63. 63 /**
  64. 64 * 读取消息长度
  65. 65 * 消息格式为:消息长度+消息内容
  66. 66 * @param is
  67. 67 * @return
  68. 68 * @throws IOException
  69. 69 */
  70. 70 public static int readLen(InputStream is) throws IOException {
  71. 71 int b1 = is.read();
  72. 72 int b2 = is.read();
  73. 73 int b3 = is.read();
  74. 74 int b4 = is.read();
  75. 75 int len = (b1 << 24) + (b2 << 16) + (b3 << 8) + b4;
  76. 76 return len;
  77. 77 }
  78. 78
  79. 79 /**
  80. 80 * int 转 byte[] 数组
  81. 81 * @param len
  82. 82 * @return
  83. 83 */
  84. 84 public static byte[] int2byte(int len) {
  85. 85 byte[] b = new byte[4];
  86. 86 b[0] = (byte) (len >> 24);
  87. 87 b[1] = (byte) (len >> 16 & 0XFF);
  88. 88 b[2] = (byte) (len >> 8 & 0XFF);
  89. 89 b[3] = (byte) (len & 0XFF);
  90. 90 return b;
  91. 91 }
  92. 92 }
  93. 93

Socket 实现聊天功能的更多相关文章

  1. socket实现聊天功能(二)

    socket实现聊天功能(二) WebSocket协议是建立在HTTP协议之上,因此创建websocket服务时需要调用http模块的createServer方法.将生成的server作为参数传入so ...

  2. 使用socket实现聊天功能

    public class Service { //服务器 public static void main(String[] args) { ServerSocket serverSocket=null ...

  3. 我们一起学习WCF 第九篇聊天功能

    说到聊天,那么其实就是传输数据,把自己写的东西传给自己想发送的那么人.我总结一下传输常见的有三种方式 1:就是我们常见的数据库传输 2:就是文件(流)传输 3:就是socket传输 今天我们说的wcf ...

  4. Socket.IO聊天室~简单实用

    小编心语:大家过完圣诞准备迎元旦吧~小编在这里预祝大家元旦快乐!!这一次要分享的东西小编也不是很懂啊,总之小编把它拿出来是觉地比较稀奇,而且程序也没有那么难,是一个比较简单的程序,大家可以多多试试~ ...

  5. Android 基于Socket的聊天应用(二)

    很久没写BLOG了,之前在写Android聊天室的时候答应过要写一个客户(好友)之间的聊天demo,Android 基于Socket的聊天室已经实现了通过Socket广播形式的通信功能. 以下是我写的 ...

  6. Linux下p2p的聊天功能实现

    Linux下p2p的聊天功能实现细节 Do one thing at a time, and do well. 今天闲着没事,写一个P2P的点对点的聊天功能的小程序,我觉得对网络编程初学者的学习很有用 ...

  7. windows phone 8.1开发:socket通信聊天

    本例用WPF程序做服务器端,windows phone程序做客户端.我们使用基于UDP协议的Socket通信.更多关于socket信息请查看:http://msdn.microsoft.com/zh- ...

  8. Spring 学习——基于Spring WebSocket 和STOMP实现简单的聊天功能

    本篇主要讲解如何使用Spring websocket 和STOMP搭建一个简单的聊天功能项目,里面使用到的技术,如websocket和STOMP等会简单介绍,不会太深,如果对相关介绍不是很了解的,请自 ...

  9. 使用websocket实现在线聊天功能

    很早以前为了快速达到效果,使用轮询实现了在线聊天功能,后来无意接触了socket,关于socket我的理解是进程间通信,首先要有服务器跟客户端,服务的启动监听某ip端口定位该进程,客户端开启socke ...

随机推荐

  1. SQL Server 日期函数大全

    一.统计语句 1.--统计当前[>当天00点以后的数据] SELECT * FROM 表 WHERE CONVERT(Nvarchar, dateandtime, 111) = CONVERT( ...

  2. 定义get/set方法快捷方式

    定义get/set方法可以通过鼠标进行完成,这里有一个简单的通过编辑器默认生成getter/setter,编辑器会生成默认生成get/set方法 第一步:右键鼠标,如图所示选择 第二步:点击OK就可以 ...

  3. CodeForces834D DP + 线段树

    http://codeforces.com/problemset/problem/834/D 将一个长度为n的序列分为k段 使得总价值最大一段区间的价值表示为区间内不同数字的个数 n<=3500 ...

  4. Hadoop生态圈-Cloudera Manager扫盲篇

    Hadoop生态圈-Cloudera Manager扫盲篇 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在讨论CDH.cloueramamager之前,我要问大家几个问题: 1& ...

  5. MYCAT分库分表

    一.整体架构 1.192.168.189.130:mysql master服务,两个数据库db_store.db_user,db_store做了主从复制 db_user: 用户表users为分片表 数 ...

  6. IOS绘图的核心步骤

    在view上绘制一个图形的方式有很多种,表现形式可能不一样,但其实质步骤都是一样的: 1)获取上下文 2)绘制路径 3)添加路径到上下文 4)修改图形状态参数 5)渲染上下文 下面我们以画一个圆形来演 ...

  7. Swift真机调试时报错dyld: Library not loaded: @rpath/libswiftCore.dylib

    dyld: Library not loaded: @rpath/libswiftCore.dylib Referenced from: /private/var/mobile/Containers/ ...

  8. 解决vue <router-link>在IE与火狐上点击失效(路由不跳转)问题

    <router-link to="/GoAbroad"> </router-link> vue中的<router-link>这种声明式的路由方式 ...

  9. sublime 将打字内容放在屏幕中央

    在settings user里添加一句: "scroll_past_end": true

  10. C# 优化程序的四十七种方法

    一.用属性代替可访问的字段 1..NET数据绑定只支持数据绑定,使用属性可以获得数据绑定的好处: 2.在属性的get和set访问器重可使用lock添加多线程的支持. 二.readonly(运行时常量) ...