<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          模擬QQ群聊和私聊(網(wǎng)絡(luò)編程+多線程)

          共 19763字,需瀏覽 40分鐘

           ·

          2021-04-10 12:53

          一、聊天演示

          這個是我自己模擬的截圖,由于只有一臺電腦,故只能運行多個窗口進行演示,這里的服務(wù)器端是Server,客戶端有三個分別是111、222和333,當我們正常聊天時是群聊狀態(tài),想要進行私聊可以進行@XXX:即可,該系統(tǒng)可以完成多臺電腦的聯(lián)機,已實驗

          二、服務(wù)器端

          下面給大家詳細的講解一下關(guān)于QQ群聊和私聊的具體思想,首先這個程序用了TCP協(xié)議,也叫做三次握手協(xié)議,為什么這樣講呢,是因為在這個TCP協(xié)議中分客戶端和服務(wù)器端,客戶端要想向服務(wù)器端發(fā)送消息,首先要先給服務(wù)器打個招呼,看看服務(wù)器是否能正常工作,如果可以,服務(wù)器會給一個回復(fù),當客戶端接到這個肯定的回復(fù)后才能向服務(wù)器發(fā)送消息,所以需要先啟動服務(wù)器端,其中,服務(wù)器端和客戶端之間的信息傳輸都是以流的方式進行的,如何啟動服務(wù)器端呢,這個是我寫的代碼,里面都有注釋:

          package com.TCP;

          import java.io.DataInputStream;
          import java.io.DataOutputStream;
          import java.io.IOException;
          import java.net.ServerSocket;
          import java.net.Socket;
          import java.util.ArrayList;
          import java.util.List;

          /**
           * 該類實現(xiàn)的是服務(wù)器端,也只有啟動了服務(wù)器,客戶端才能進行信息的交流
           * @author 11852
           *
           */


          public class Server {

              //這個list集合是用來存儲各個客戶端的,每當有一個客戶端建立了連接,這里就會存儲起來
              private static List<Channel> list = new ArrayList<Channel>();

              public static void main(String[] args) throws IOException {
                  System.out.println("---Server---");
                  // 指定端口,使用ServerSocket創(chuàng)建服務(wù)器,此時創(chuàng)建了一個名字為server端口號為12345的服務(wù)器
                  ServerSocket server = new ServerSocket(12345);

                  boolean flag = true;
                  while (flag) {
                      // 阻塞式等待連接accept,服務(wù)器調(diào)用accept方法,即是獲得一個客戶端的連接
                      //如果沒有客戶端連接,則該程序處于堵塞狀態(tài)
                      Socket client = server.accept();
                      System.out.println("一個客戶端建立了連接");

                      //客戶端與服務(wù)器建立了連接之后,獲取該客戶端的輸入流和輸出流對象
                      Channel channel = new Channel(client);
                      list.add(channel);// 用list容器管理所有的人員
                      //這里是實現(xiàn)多線程,即每個客戶端都可以進行與服務(wù)器端的交流
                      new Thread(channel).start();
                  }
                  server.close();
              }

              // 一個客戶端代表一個Channel
              static class Channel implements Runnable {
                  private DataInputStream dis;
                  private DataOutputStream dos;
                  private Socket client;
                  private boolean isRunning;
                  private String name;

                  //這是構(gòu)造方法
                  public Channel(Socket client) {
                      this.client = client;
                      try {
                          dis = new DataInputStream(client.getInputStream());
                          isRunning = true;
                          name = receive();
                      } catch (IOException e) {
                          relese();
                      }
                      try {
                          dos = new DataOutputStream(client.getOutputStream());
                      } catch (IOException e) {
                          relese();
                      }
                  }

                  // 接收消息
                  private String receive() {
                      String msg = "";
                      try {
                          msg = dis.readUTF();
                      } catch (IOException e) {
                          relese();
                      }
                      return msg;
                  }

                  // 發(fā)送消息
                  private void send(String msg) {
                      try {
                          dos.writeUTF(msg);
                      } catch (IOException e) {
                          relese();
                      }
                  }

                  // 群聊,發(fā)給別人
                  private void sendOthers(String msg) {

                      // 私聊格式@XXX:這里是找到以@開頭的信息
                      if (msg.startsWith("@")) {
                          int idx = msg.indexOf(":");
                          String targetName = msg.substring(1, idx);
                          msg = msg.substring(idx + 1);
                          for (Channel other : list) {
                              if (other.name.equals(targetName)) {
                                  other.send(this.name + ":" + msg);
                              }
                          }
                      } else {
                          for (Channel other : list) {
                              if (other == this) {
                                  continue;
                              } else {
                                  other.send(this.name + ":" + msg);
                              }

                          }
                      }
                  }

                  // 釋放資源
                  private void relese() {
                      this.isRunning = false;
                      //這里的Util是自定義的一個類
                      Util.close(dis, dos, client);
                  }

                  @Override
                  public void run() {
                      while (isRunning) {
                          String msg = receive();
                          if (!msg.equals("")) {
                              sendOthers(msg);
                          }
                      }
                  }
              }
          }

          三、客戶端

          客戶端中用到了接收信息、發(fā)送信息以及釋放資源

          package com.TCP;

          import java.io.BufferedReader;
          import java.io.IOException;
          import java.io.InputStreamReader;
          import java.net.Socket;

          public class Client {
              public static void main(String[] args) throws IOException {
                  System.out.println("---Client---");

                  BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                  System.out.println("請輸入用戶名");
                  String name = br.readLine();
                  // 建立連接,使用Socket創(chuàng)建連接,括號內(nèi)是服務(wù)器的地址和端口
                  Socket client = new Socket("localhost"12345);

                  // 客戶端發(fā)送消息
                  new Thread(new Send(client, name)).start();
                  new Thread(new Receive(client)).start();
              }
          }

          在實現(xiàn)客戶端的時候,我這里是在控制臺輸入的信息,也可以進行跨級聊天,但前提是要在同一個局域網(wǎng)內(nèi),對于客戶端來說,需要客服端進行發(fā)送信息和接收信息,首先看看接收信息吧

          package com.TCP;

          import java.io.DataInputStream;
          import java.io.IOException;
          import java.net.Socket;

          public class Receive implements Runnable {
              private DataInputStream dis;
              private Socket client;
              private boolean isRunning;

              //這里是傳過來了一個客戶端對象,并獲得了輸入流對象
              public Receive(Socket client) {
                  this.client = client;
                  try {
                      dis = new DataInputStream(client.getInputStream());
                      isRunning = true;
                  } catch (IOException e) {
                      release();
                  }
              }

              //這里是實現(xiàn)了獲取信息
              private String receive() {
                  String msg = "";
                  try {
                      msg = dis.readUTF();
                  } catch (IOException e) {
                      release();
                  }
                  return msg;
              }

              //這是重寫了run方法,實現(xiàn)多線程,也就是多個客戶端都能與服務(wù)器打交道
              @Override
              public void run() {
                  while (isRunning) {
                      String msg = receive();
                      if (!msg.equals("")) {
                          System.out.println(msg);
                      }
                  }
              }

              // 釋放資源
              private void release() {
                  this.isRunning = false;
                  Util.close(dis, client);
              }
          }

          然后就是發(fā)送類了,發(fā)送跟接收差不多,基本思路是一樣的

          package com.TCP;

          import java.io.BufferedReader;
          import java.io.DataOutputStream;
          import java.io.IOException;
          import java.io.InputStreamReader;
          import java.net.Socket;

          public class Send implements Runnable {
              private BufferedReader console;
              private DataOutputStream dos;
              private Socket client;
              private boolean isRunning;

              // 這里用到了名字,就是知道是誰誰發(fā)的信息
              public Send(Socket client, String name) {
                  console = new BufferedReader(new InputStreamReader(System.in));
                  this.client = client;
                  try {
                      dos = new DataOutputStream(client.getOutputStream());
                      this.isRunning = true;
                      send(name);

                  } catch (IOException e) {
                      release();
                  }
              }

              // 這里是重寫了run方法
              @Override
              public void run() {
                  while (isRunning) {
                      String msg = getStrFromConsole();
                      if (!msg.equals("")) {
                          send(msg);
                      }

                  }

              }

              // 這里是發(fā)送消息
              private void send(String msg) {
                  try {
                      dos.writeUTF(msg);
                      dos.flush();
                  } catch (IOException e) {
                      release();
                  }
              }

              // 這里是獲取控制臺輸入的信息
              private String getStrFromConsole() {
                  String msg = "";
                  try {
                      msg = console.readLine();
                  } catch (IOException e) {
                      release();
                  }
                  return msg;
              }

              // 釋放資源
              private void release() {
                  this.isRunning = false;
                  Util.close(dos, client);
              }
          }

          四、Util工具類

          package com.TCP;

          import java.io.Closeable;

          /**
           * 工具類
           * 
           * @author 11852
           *
           */

          public class Util {

              // 釋放資源
              public static void close(Closeable... targets) {
                  for (Closeable target : targets) {
                      try {
                          if (target != null) {
                              target.close();
                          }
                      } catch (Exception e) {
                          e.printStackTrace();
                      }
                  }
              }
          }
          瀏覽 157
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产精品直接观看 | 伊人成人电影综合网 | 欧美成人极品 | 黄色电影在线观看国内免费 | 欧美老女人黄片 |