基于Socket编程的聊天工具【Java实现】

思路:

要实现聊天功能,我们就必须有服务器和客户端。客户端连接到服务器,然后通过发送消息到服务器及从服务器读取消息来达到多客户端通信的目的。简单来说,所有客户端都是通过服务器来进行身份验证和消息发送的。要达到通信的目的,我们首先要做的是实现多客户端与服务器的连接,当客户端连接上服务器之后,服务器需要做的就是每来一个客户端,就处理该客户端的业务,如登录,单聊等;客户端要做的就是通过读取服务器的数据、写入数据到服务器来实现与其他客户端的交互。

先通过两张图了解一下客户端与服务器的交互:

了解完大体思路之后,接下来我们来看一下各个步骤的具体实现方法:

  • 客户端与服务器的连接

套接字使用TCP可以实现两台计算机之间的通信,客户端创建一个套接字,并尝试连接服务器的套接字。java.net.Socket类代表一个套接字,java.net.ServerSocket类为服务器提供了一种监听并连接的通信机制。在连接过程中:

1. 服务器会创建一个ServerSocket对象,表示通过服务器的端口进行通信。

public ServerSocket(int port) throws IOExecption  //创建绑定到特定端口的服务器套接字

2. 服务器调用ServerSocket类的accept()方法,该方法将阻塞等待客户端的连接。

public Socket accept() throws IOException  //侦听并接收到此套接字的连接

3. 当服务器在等待客户端连接时,此时一个客户端创建一个Socket对象,并指定服务器名称和端口号请求连接。

  1. public Socket(String host, int port) throws UnknownHostException, IOException. 创建一个
  2. 流套接字并将其连接到指定主机上的指定端口号。

4. 当客户端连接上服务器之后,在服务器端,accept()方法会返回一个新的socket引用,该socket连接到客户端的socket。

 

  • 服务器的工作

当客户端连接上服务器之后,我们知道accept()方法会返回给服务器一个新的socket引用,该socket连接到客户端的socket。那么此时只要有一个客户端连接到服务器了,服务器就要处理客户端的业务。我们知道每个客户端其实都是独立的,而且每个客户端连接服务器的时间都不定,所以我们可以创建一个线程池,每来一个客户端,就将该客户端的业务提交到线程池中,由线程池执行器来执行任务。由于每个客户的业务需求不同,我们可以创建一个类(ExecuteClient)专门来处理客户的业务。

  • 客户端的工作

当客户端连接上服务器之后,每一个客户端都会有一个Socket对象,该对象通过往服务器写入数据,从服务器读取数据可以实现不同客户端之间的通信。这时候我们也可以创建两个线程专门处理往服务器写入数据(WriteDataToServerThread)和从服务器读取数据(ReadDataFromServerThread)的功能。

那么服务器可以处理客户端的哪些业务呢?

由于客户端和服务器都有Socket对象,我们先来看看它们都能调用哪些方法:

  1. public InputStream getInputStream() throws IOException //返回此套接字的输入流
  2. public OutputStream getOutputStream() throws IOException //返回此套接字的输出流
  3. public void close() throws IOException //关闭此套接字

此前我们先做如下约定:

1. 当输入register:<userName>:<password>时,表示用户注册

2. 当输入login:<userName>:<password>时,表示用户登录

3.当输入private:<userName>:<message>时,表示单聊

4.当输入group:<message>时,表示群聊

5.当输入bye时,表示用户退出

  • 注册(register)

注册的时候有以下几点要求:

1. 用户名、密码均不能为空
2. 用户名、密码都仅支持字母和数字
3. 用户名长度:8-15,密码长度:6-10
4. 用户名不能重复,密码无要求
5. 注册信息存储(用户名+密码)

思路:当新用户注册时,首先会输入用户名和密码,在用户名和密码均满足上述要求时,我们需要对用户信息(用户名+密码)进行存储,以便再有新用户要注册时进行用户名是否重复的比较。在保存用户信息时,由于一个用户名对应一个密码,我们可以用Map<String,String>  USER_PASSWORD_MAP来保存,其中key为用户名,value为密码。当新用户注册成功后,告知该用户注册成功;否则将注册失败原因告知,如用户名重复,密码长度不对等。

  1. //给客户端发送信息
  2. private void sendMessage(Socket client, String message) {
  3. try {
  4. OutputStream clientOutput = client.getOutputStream();
  5. OutputStreamWriter writer = new OutputStreamWriter(clientOutput);
  6. writer.write(message + "\n");
  7. writer.flush();
  8. } catch (IOException e) {
  9. e.printStackTrace();
  10. }
  11. }

  12. //注册
  13. private void register(String userName, String password, Socket client) {
  14. if (userName == null) {
  15. this.sendMessage(client, "用户名不能为空");
  16. return;
  17. }
  18. if (password == null) {
  19. this.sendMessage(client, "密码不能为空");
  20. return;
  21. }

  22. char[] name = userName.toCharArray(); //字符串转数组
  23. char[] passWord = password.toCharArray(); //字符串转数组
  24. int nLength = name.length; //用户名的长度
  25. int pLength = passWord.length; //密码的长度
  26. if (!((nLength >= 8 && nLength <= 15) && (pLength >= 6 && pLength <= 10))) {
  27. this.sendMessage(client, "输入的用户名或密码长度不符合要求(用户名长度8到15,密码长度6到10)");
  28. return;
  29. }


  30. for (char n : name) {
  31. if (!((n >= 'A' && n <= 'Z') || (n >= 'a' && n <= 'z') || (n >= '0' && n <= '9'))) {
  32. this.sendMessage(client, "用户名仅支持字母、数字");
  33. return;
  34. }
  35. }
  36. for (char p : passWord) {
  37. if (!((p >= 'A' && p <= 'Z') || (p >= 'a' && p <= 'z') || (p >= '0' && p <= '9'))) {
  38. this.sendMessage(client, "密码仅支持字母、数字");
  39. return;
  40. }
  41. }


  42. for (Map.Entry<String, String> entry : USER_PASSWORD_MAP.entrySet()) {
  43. if (userName.equals(entry.getKey())) {
  44. this.sendMessage(client, "用户名" + userName + "已被占用");
  45. return;
  46. }
  47. }
  48. USER_PASSWORD_MAP.put(userName, password); //保存新注册的用户信息
  49. this.sendMessage(this.client, "用户" + userName + "注册成功"); //通知客户端注册成功
  50. }
  • 登录(login)

登录的时候有以下几点要求:

 1. 用户名密码均正确
 2. 在线用户、离线用户存储
 3. 在线用户不能重复登录,离线用户可以再次登录

思路: 当用户注册并登录成功后,我们可以将其保存在在线用户中,以此来检测是否有在线用户重复登录;当用户离线后,将其保存在离线用户中。由于一个用户名对应一个用户,所以我们可以用Map<String,Socket> ONLINE_USER_MAP保存在线用户,Map<String,Socket> OFFLINE_USER_MAP保存离线用户。如果用户登录成功,则发送“用户登录成功”给该用户,否则发送未登录成功的原因,如用户名或密码不正确,在线用户不能重复登录等。

  1. //给客户端发送信息
  2. private void sendMessage(Socket client, String message) {
  3. try {
  4. OutputStream clientOutput = client.getOutputStream();
  5. OutputStreamWriter writer = new OutputStreamWriter(clientOutput);
  6. writer.write(message + "\n");
  7. writer.flush();
  8. } catch (IOException e) {
  9. e.printStackTrace();
  10. }
  11. }

  12. //登录
  13. private void login(String userName, String password, Socket client) {
  14. for (Map.Entry<String, Socket> entry : ONLINE_USER_MAP.entrySet()) {
  15. if (userName.equals(entry.getKey())) {
  16. this.sendMessage(client, "用户" + userName + "已在线,不可重复登录");
  17. return;
  18. }
  19. }
  20. for (Map.Entry<String, String> entry : USER_PASSWORD_MAP.entrySet()) {
  21. if (userName.equals(entry.getKey()) && password.equals(entry.getValue())) {
  22. System.out.println("用户" + userName + "加入聊天室");
  23. ONLINE_USER_MAP.put(userName, client); //将登录成功的用户存入 在线用户
  24. printOnlineUser(); //打印在线用户
  25. this.sendMessage(client, "用户" + userName + "登录成功"); //通知客户端登录成功
  26. return;
  27. }
  28. }
  29. this.sendMessage(client, "用户名或密码输入不正确");
  30. return;
  31. }
  • 单聊(privateChat)

单聊的时候有以下几点要求:

1. 不能自己给自己发消息
2. 不支持给离线用户发送消息 

思路:我们知道单聊是一个用户(currentUserName)给另一个用户(target) 发消息(message),那么为了用户更好的体验,在发送信息时,我们应该将发送者的用户名告知给被发送者。如果被发送者是自己,则不发送信息;如果被发送者已离线,则告知发送者被发送者已离线。

  1. //获取当前用户的用户名
  2. private String getCurrentUserName() {
  3. String currentUserName = null;
  4. for (Map.Entry<String, Socket> entry : ONLINE_USER_MAP.entrySet()) {
  5. if (entry.getValue().equals(this.client)) {
  6. currentUserName = entry.getKey();
  7. break;
  8. }
  9. }
  10. return currentUserName;
  11. }

  12. //给客户端发送信息
  13. private void sendMessage(Socket client, String message) {
  14. try {
  15. OutputStream clientOutput = client.getOutputStream();
  16. OutputStreamWriter writer = new OutputStreamWriter(clientOutput);
  17. writer.write(message + "\n");
  18. writer.flush();
  19. } catch (IOException e) {
  20. e.printStackTrace();
  21. }
  22. }

  23. //单聊
  24. private void privateChat(String userName, String message) {
  25. String currentUserName = this.getCurrentUserName();
  26. Socket target = ONLINE_USER_MAP.get(userName);
  27. if (currentUserName.equals(userName)) { //不能自己给自己发消息
  28. return;
  29. }
  30. if (target != null) {
  31. this.sendMessage(target, currentUserName + "对你说:" + message);
  32. } else {
  33. this.sendMessage(this.client, "用户" + userName + "已下线,此条消息未发出");
  34. }
  35. }
  • 群聊(groupChat)

群聊的时候有以下几点要求:

1. 发送者发出的消息只显示给其他在线用户(不包括发送者本人)

思路:群聊即一个用户发了消息,其他在线用户都能收到消息并做出回应。

  1. //获取当前用户的用户名
  2. private String getCurrentUserName() {
  3. String currentUserName = null;
  4. for (Map.Entry<String, Socket> entry : ONLINE_USER_MAP.entrySet()) {
  5. if (entry.getValue().equals(this.client)) {
  6. currentUserName = entry.getKey();
  7. break;
  8. }
  9. }
  10. return currentUserName;
  11. }

  12. //给客户端发送信息
  13. private void sendMessage(Socket client, String message) {
  14. try {
  15. OutputStream clientOutput = client.getOutputStream();
  16. OutputStreamWriter writer = new OutputStreamWriter(clientOutput);
  17. writer.write(message + "\n");
  18. writer.flush();
  19. } catch (IOException e) {
  20. e.printStackTrace();
  21. }
  22. }

  23. //群聊
  24. private void groupChat(String message) {
  25. String currentUserName = this.getCurrentUserName();
  26. for (Socket socket : ONLINE_USER_MAP.values()) {
  27. if (socket.equals(this.client)) {
  28. continue;
  29. }
  30. this.sendMessage(socket, currentUserName + "说:" + message);
  31. }
  32. }
  • 退出(quit)

思路:因为客户端每输入一句话都会发给服务器,然后服务器根据用户输入的信息作出相应的处理。当用户输入bye时,表明用户要退出,此时用户将关闭客户端,且停止往服务器写入数据功能。当服务器收到用户发送的bye之后,服务器将该用户从在线用户中去除,之后发送bye给用户,通知用户可以退出了。

  1. //获取当前用户的用户名
  2. private String getCurrentUserName() {
  3. String currentUserName = null;
  4. for (Map.Entry<String, Socket> entry : ONLINE_USER_MAP.entrySet()) {
  5. if (entry.getValue().equals(this.client)) {
  6. currentUserName = entry.getKey();
  7. break;
  8. }
  9. }
  10. return currentUserName;
  11. }

  12. //退出
  13. private void quit() {
  14. String currentUserName = this.getCurrentUserName();
  15. System.out.println("用户" + currentUserName + "下线");
  16. Socket socket = ONLINE_USER_MAP.get(currentUserName);
  17. this.sendMessage(socket, "bye");

  18. ONLINE_USER_MAP.remove(currentUserName);
  19. printOnlineUser();
  20. OFFLINE_USER_MAP.put(currentUserName, socket);
  21. printOfflineUser();

  22. }

完整源代码如下:

github地址:https://github.com/huiforeverlin/chat_room

服务器:

  1. import java.io.IOException;
  2. import java.net.ServerSocket;
  3. import java.net.Socket;
  4. import java.util.concurrent.ExecutorService;
  5. import java.util.concurrent.Executors;


  6. //服务器主类
  7. public class MultiThreadServer {
  8. public static void main(String[] args) {
  9. final ExecutorService executorService = Executors.newFixedThreadPool(10);//核心线程10个
  10. int port = 6666;//默认端口
  11. try {
  12. if (args.length > 0) { //命令行参数大于0,则将第一个参数作为端口值
  13. port = Integer.parseInt(args[0]);
  14. }
  15. } catch (NumberFormatException e) {
  16. System.out.println("端口参数不正确,将采用默认端口:" + port);
  17. }
  18. try {
  19. ServerSocket serverSocket = new ServerSocket(port); //servereSocket表示服务器
  20. System.out.println("等待客户端连接...");
  21. while (true) {
  22. Socket client = serverSocket.accept(); //支持多客户端连接
  23. System.out.println("客户端连接端口号:" + client.getPort());
  24. executorService.submit(new ExecuteClient(client)); //通过提交任务到线程池来执行每个客户的业务
  25. }
  26. } catch (IOException e) {
  27. e.printStackTrace();
  28. }
  29. }
  30. }
  1. import java.io.IOException;
  2. import java.io.InputStream;
  3. import java.io.OutputStream;
  4. import java.io.OutputStreamWriter;
  5. import java.net.Socket;
  6. import java.util.Map;
  7. import java.util.Scanner;
  8. import java.util.concurrent.ConcurrentHashMap;


  9. //执行客户业务
  10. public class ExecuteClient implements Runnable {
  11. private final Socket client; //客户
  12. private static final Map<String, Socket> ONLINE_USER_MAP = new ConcurrentHashMap<String, Socket>();//在线用户
  13. private static final Map<String, Socket> OFFLINE_USER_MAP = new ConcurrentHashMap<String, Socket>();//离线用户
  14. private static final Map<String, String> USER_PASSWORD_MAP = new ConcurrentHashMap<>(); //用户信息(用户名,密码)

  15. public ExecuteClient(Socket client) {
  16. this.client = client;
  17. }

  18. //实现run方法
  19. public void run() {
  20. try {
  21. InputStream clientInput = client.getInputStream(); //从客户端读取数据
  22. Scanner scanner = new Scanner(clientInput);
  23. while (true) {
  24. String line = scanner.nextLine();
  25. if (line.startsWith("register")) { //注册
  26. String[] segments = line.split("\\:");
  27. String userName = segments[1]; //第一个参数表示用户名
  28. String password = segments[2]; //第二个参数表示密码
  29. this.register(userName, password, client);
  30. continue;
  31. }
  32. if (line.startsWith("login")) { //登录
  33. String[] segments = line.split("\\:");
  34. String userName = segments[1]; //第一个参数表示用户名
  35. String password = segments[2]; //第二个参数表示密码
  36. this.login(userName, password, client);
  37. continue;
  38. }
  39. if (line.startsWith("private")) { //单聊
  40. String[] segments = line.split("\\:");
  41. String userName = segments[1]; //第一个参数表示被发送者的名称
  42. String message = segments[2]; //第二个参数表示要发送的信息
  43. this.privateChat(userName, message);
  44. continue;
  45. }
  46. if (line.startsWith("group")) { //群聊
  47. String message = line.split("\\:")[1]; //要发送的信息
  48. this.groupChat(message);
  49. continue;
  50. }
  51. if (line.startsWith("bye")) { //退出
  52. this.quit();
  53. break;
  54. }
  55. }
  56. } catch (IOException e) {
  57. e.printStackTrace();
  58. }
  59. }


  60. //注册
  61. private void register(String userName, String password, Socket client) {
  62. if (userName == null) {
  63. this.sendMessage(client, "用户名不能为空");
  64. return;
  65. }
  66. if (password == null) {
  67. this.sendMessage(client, "密码不能为空");
  68. return;
  69. }

  70. char[] name = userName.toCharArray(); //字符串转数组
  71. char[] passWord = password.toCharArray(); //字符串转数组
  72. int nLength = name.length; //用户名的长度
  73. int pLength = passWord.length; //密码的长度
  74. if (!((nLength >= 8 && nLength <= 15) && (pLength >= 6 && pLength <= 10))) {
  75. this.sendMessage(client, "输入的用户名或密码长度不符合要求(用户名长度8到15,密码长度6到10)");
  76. return;
  77. }


  78. for (char n : name) {
  79. if (!((n >= 'A' && n <= 'Z') || (n >= 'a' && n <= 'z') || (n >= '0' && n <= '9'))) {
  80. this.sendMessage(client, "用户名仅支持字母、数字");
  81. return;
  82. }
  83. }
  84. for (char p : passWord) {
  85. if (!((p >= 'A' && p <= 'Z') || (p >= 'a' && p <= 'z') || (p >= '0' && p <= '9'))) {
  86. this.sendMessage(client, "密码仅支持字母、数字");
  87. return;
  88. }
  89. }


  90. for (Map.Entry<String, String> entry : USER_PASSWORD_MAP.entrySet()) {
  91. if (userName.equals(entry.getKey())) {
  92. this.sendMessage(client, "用户名" + userName + "已被占用");
  93. return;
  94. }
  95. }
  96. USER_PASSWORD_MAP.put(userName, password); //保存新注册的用户信息
  97. this.sendMessage(this.client, "用户" + userName + "注册成功"); //通知客户端注册成功
  98. }


  99. //登录
  100. private void login(String userName, String password, Socket client) {
  101. for (Map.Entry<String, Socket> entry : ONLINE_USER_MAP.entrySet()) {
  102. if (userName.equals(entry.getKey())) {
  103. this.sendMessage(client, "用户" + userName + "已在线,不可重复登录");
  104. return;
  105. }
  106. }
  107. for (Map.Entry<String, String> entry : USER_PASSWORD_MAP.entrySet()) {
  108. if (userName.equals(entry.getKey()) && password.equals(entry.getValue())) {
  109. System.out.println("用户" + userName + "加入聊天室");
  110. ONLINE_USER_MAP.put(userName, client); //将登录成功的用户存入 在线用户
  111. printOnlineUser(); //打印在线用户
  112. this.sendMessage(client, "用户" + userName + "登录成功"); //通知客户端登录成功
  113. return;
  114. }
  115. }
  116. this.sendMessage(client, "用户名或密码输入不正确");
  117. return;
  118. }


  119. //单聊
  120. private void privateChat(String userName, String message) {
  121. String currentUserName = this.getCurrentUserName();
  122. Socket target = ONLINE_USER_MAP.get(userName);
  123. if (currentUserName.equals(userName)) { //不能自己给自己发消息
  124. return;
  125. }
  126. if (target != null) {
  127. this.sendMessage(target, currentUserName + "对你说:" + message);
  128. } else {
  129. this.sendMessage(this.client, "用户" + userName + "已下线,此条消息未发出");
  130. }
  131. }

  132. //群聊
  133. private void groupChat(String message) {
  134. String currentUserName = this.getCurrentUserName();
  135. for (Socket socket : ONLINE_USER_MAP.values()) {
  136. if (socket.equals(this.client)) {
  137. continue;
  138. }
  139. this.sendMessage(socket, currentUserName + "说:" + message);
  140. }
  141. }

  142. //退出
  143. private void quit() {
  144. String currentUserName = this.getCurrentUserName();
  145. System.out.println("用户" + currentUserName + "下线");
  146. Socket socket = ONLINE_USER_MAP.get(currentUserName);
  147. this.sendMessage(socket, "bye");

  148. ONLINE_USER_MAP.remove(currentUserName);
  149. printOnlineUser();
  150. OFFLINE_USER_MAP.put(currentUserName, socket);
  151. printOfflineUser();

  152. }


  153. //给客户端发送信息
  154. private void sendMessage(Socket client, String message) {
  155. try {
  156. OutputStream clientOutput = client.getOutputStream();
  157. OutputStreamWriter writer = new OutputStreamWriter(clientOutput);
  158. writer.write(message + "\n");
  159. writer.flush();
  160. } catch (IOException e) {
  161. e.printStackTrace();
  162. }
  163. }

  164. //获取当前用户的用户名
  165. private String getCurrentUserName() {
  166. String currentUserName = null;
  167. for (Map.Entry<String, Socket> entry : ONLINE_USER_MAP.entrySet()) {
  168. if (entry.getValue().equals(this.client)) {
  169. currentUserName = entry.getKey();
  170. break;
  171. }
  172. }
  173. return currentUserName;
  174. }

  175. //打印在线用户
  176. private void printOnlineUser() {
  177. System.out.println("在线用户人数:" + ONLINE_USER_MAP.size() + ", 用户列表:");
  178. for (Map.Entry<String, Socket> entry : ONLINE_USER_MAP.entrySet()) {
  179. System.out.print(entry.getKey() + " ");
  180. }
  181. System.out.println("");
  182. }

  183. //打印离线用户
  184. private void printOfflineUser() {
  185. System.out.println("离线用户人数:" + OFFLINE_USER_MAP.size() + ", 离线用户:");
  186. for (Map.Entry<String, Socket> entry : OFFLINE_USER_MAP.entrySet()) {
  187. System.out.print(entry.getKey() + " ");
  188. }
  189. System.out.println("");
  190. }
  191. }

客户端:

  1. import java.io.IOException;
  2. import java.net.Socket;


  3. //客户端主类
  4. public class MultiThreadClient {
  5. public static void main(String[] args) {
  6. try {
  7. String host = "127.0.0.1";
  8. int port = 6666;
  9. try {
  10. if (args.length > 0) {
  11. port = Integer.parseInt(args[0]);
  12. }
  13. } catch (NumberFormatException e) {
  14. System.out.println("端口参数不正确,将采用默认端口:" + port);
  15. }
  16. if (args.length > 1) {
  17. host = args[1];
  18. }

  19. final Socket client = new Socket(host, port);
  20. new WriteDataToServerThread(client).start();
  21. new ReadDataFromServerThread(client).start();
  22. } catch (IOException e) {
  23. e.printStackTrace();
  24. }
  25. }
  26. }
  1. import java.io.IOException;
  2. import java.io.InputStream;
  3. import java.net.Socket;
  4. import java.util.Scanner;


  5. //从服务器读取数据
  6. public class ReadDataFromServerThread extends Thread {
  7. private final Socket client;

  8. public ReadDataFromServerThread(Socket client) {
  9. this.client = client;
  10. }

  11. @Override
  12. public void run() {
  13. try {
  14. InputStream clientInput = client.getInputStream();
  15. Scanner scanner = new Scanner(clientInput);
  16. while (true) {
  17. String message = scanner.nextLine();
  18. System.out.println("来自服务器的消息:" + message);
  19. if (message.equals("bye")) {
  20. break;
  21. }
  22. }
  23. } catch (IOException e) {
  24. e.printStackTrace();
  25. }
  26. }
  27. }
  1. import java.io.IOException;
  2. import java.io.OutputStream;
  3. import java.io.OutputStreamWriter;
  4. import java.net.Socket;
  5. import java.util.Scanner;


  6. //往服务器写入数据
  7. public class WriteDataToServerThread extends Thread {
  8. private final Socket client;

  9. public WriteDataToServerThread(Socket client) {
  10. this.client = client;
  11. }

  12. @Override
  13. public void run() {
  14. try {
  15. OutputStream clientOutput = client.getOutputStream();
  16. OutputStreamWriter writer = new OutputStreamWriter(clientOutput);
  17. Scanner scanner = new Scanner(System.in);
  18. while (true) {
  19. System.out.println("请输入消息:");
  20. String message = scanner.nextLine();
  21. writer.write(message + "\n");
  22. writer.flush();
  23. if (message.equals("bye")) {
  24. client.close(); //客户端关闭退出
  25. break;
  26. }
  27. }
  28. } catch (IOException e) {
  29. e.printStackTrace();
  30. }

  31. }
  32. }

 

(0)

相关推荐

  • SAP Commerce Cloud OAuth 实现介绍

    Oauth2 oauth2 core extension 已经取代了 webservicescommons/oauthauthorizationserver 扩展. 它将 HTTP 端点公开为 Aut ...

  • Socket编程 (连接,发送消息) (Tcp、Udp)

    本篇文章主要实现Socket在Tcp\Udp协议下相互通讯的方式.(服务器端与客户端的通讯) 1.基于Tcp协议的Socket通讯类似于B/S架构,面向连接,但不同的是服务器端可以向客户端主动推送消息 ...

  • Windows Socket和Linux Socket编程的区别

    SOCKET在原理上应该是一样的,只是不同系统的运行机置有些不同.Socket 编程 windows到Linux代码移植遇到的问题1.一些常用函数的移植http://www.vckbase.com/d ...

  • UG编程加工模块工具条程序视图精讲

    UG编程加工模块工具条程序视图精讲

  • 微信作为聊天工具,是不是真的很难用

    昨天,腾讯悄无声息的更新了"拍一拍"的部分功能.可能有人无法理解,这个被吐槽为QQ上古时代就已经实现了的"震你一下"的简陋翻版,到底有什么可更新的必要,而且所谓 ...

  • 这个聊天工具,千万不能让“媳妇”知道!

    今天"事儿哥"要给小伙伴们推荐一个非常好玩的工具,它可以把你聊天想要发的文字进行转化,然后你在微信发出去的时候,会以代码的形式出现,不知情的人,不会发现你们在聊什么,无论是趣味聊天 ...

  • Socket编程基础学习

    Socket编程基础学习

  • 微信 “高级” 聊天工具 !!

    搜罗君,每日优质搜罗 1. 今天这个软件很有意思, 在软件内输入自己想要发送的话, 会转换成一段代码. 复制这段代码到微信聊天框, 并发送出去. 然后长按你刚才发送出去的这段话, 点击 "翻 ...

  • 如何使用OpenCV和Socket进行视频聊天?

    重磅干货,第一时间送达 一.简介 在本文中,我们要构建的是视频聊天,但话音通道使用的OpenCV和Python中的Socket.流程: 创建用于一对一通信的 TCP 套接字. 从相机中获取实时流. 对 ...

  • 简易蓝牙聊天工具①:聊天服务器

    最近有很多人关心用app inventor2(以下简称AI2)进行蓝牙通信的问题,这里制作了一个简易的聊天工具,来说明如何使用AI2所提供的蓝牙组件,来实现信息的发送与接收. 在日常生活中,我们经常提 ...