最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java基于TCP協(xié)議實(shí)現(xiàn)聊天程序

 更新時(shí)間:2020年07月28日 15:20:42   作者:熱血小碼哥  
這篇文章主要為大家詳細(xì)介紹了java基于TCP協(xié)議實(shí)現(xiàn)聊天程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

JAVA程序設(shè)計(jì)之基于TCP協(xié)議的socket聊天程序 ,供大家參考,具體內(nèi)容如下

一、程序?qū)崿F(xiàn)的功能

1、進(jìn)入客戶(hù)端界面
2、創(chuàng)建昵稱(chēng)
3、群發(fā)信息
4、@私聊
5、下線通知
6、在線人數(shù)統(tǒng)計(jì)

二、整體架構(gòu)圖

三、簡(jiǎn)單介紹

本程序?qū)崿F(xiàn)了基于TCP通信的聊天程序:

1 服務(wù)器端:

服務(wù)器端繼承JFrame框架,添加組件。創(chuàng)建服務(wù)器端的socket,起一個(gè)線程池,每接收到一個(gè)客戶(hù)端的連接,分配給其一個(gè)線程處理與客戶(hù)端的通信,將每個(gè)客戶(hù)端的昵稱(chēng)和服務(wù)器分配給其的輸出流存儲(chǔ)到哈希表中。通過(guò)檢索哈希表中昵稱(chēng)和輸出流實(shí)現(xiàn)群聊和私聊。

2 客戶(hù)端:

客戶(hù)端繼承JFrame框架,添加組件。創(chuàng)建客戶(hù)端的socket,輸入昵稱(chēng),創(chuàng)建客戶(hù)端socket對(duì)應(yīng)的輸入流輸出流,與服務(wù)器端建立通訊。

四、設(shè)計(jì)描述

本程序的實(shí)現(xiàn)是以服務(wù)器端為中繼,客戶(hù)端的所有信息都先發(fā)送給服務(wù)器端。服務(wù)器端辨別是否為私聊信息,私聊信息發(fā)送給相應(yīng)的私聊對(duì)象,否則,發(fā)送給所有的客戶(hù)端對(duì)象。

(一) 服務(wù)器端:

1.1 服務(wù)器端繼承JFrame框架,添加組件。
1.2 創(chuàng)建服務(wù)器端socket。建立一個(gè)哈希表,用于存儲(chǔ)客戶(hù)端的昵稱(chēng)以及服務(wù)器端對(duì)于每個(gè)連接的客戶(hù)端建立的輸出流。
1.3建立一個(gè)線程池,為每個(gè)連接的客戶(hù)端分配一個(gè)執(zhí)行線程。
1.3調(diào)用服務(wù)器端Socket的accept()函數(shù),等待客戶(hù)端的連接,每連接到一個(gè)客戶(hù)端,線程池給相應(yīng)的客戶(hù)端分配一個(gè)線程。
1.4每個(gè)線程內(nèi),調(diào)用服務(wù)器端Socket,封裝getOutputStream(),獲得服務(wù)器端Socket相對(duì)應(yīng)于連接的客戶(hù)端的輸出流和輸入流。輸入流首先讀取到客戶(hù)端發(fā)送來(lái)的昵稱(chēng)。將客戶(hù)端的昵稱(chēng)和服務(wù)器端的輸出流存儲(chǔ)在哈希表中,并遍歷整個(gè)哈希表,將某人上線的通知發(fā)送給所有的在線客戶(hù)端。
1.5客戶(hù)端將信息發(fā)送給服務(wù)器端,當(dāng)服務(wù)器端傳來(lái)的信息符合“@私聊對(duì)象:私聊信息”的格式時(shí),服務(wù)器端認(rèn)為這是私聊信息。服務(wù)器端將把私聊對(duì)象的昵稱(chēng)從信息中提取出來(lái),通過(guò)哈希表找到與昵稱(chēng)對(duì)應(yīng)的輸出流。將私聊信息通過(guò)輸出流發(fā)送給私聊對(duì)象。
當(dāng)不是私聊信息時(shí),服務(wù)器遍歷整個(gè)哈希表,通過(guò)每個(gè)客戶(hù)端對(duì)應(yīng)的輸出流發(fā)送給每個(gè)客戶(hù)端。
1.6當(dāng)客戶(hù)端下線時(shí),服務(wù)器端將移除哈希表中對(duì)應(yīng)存儲(chǔ)的客戶(hù)端昵稱(chēng)以及輸出流。并通知在線的每個(gè)客戶(hù)端,某人已下線。

(二) 客戶(hù)端:

2.1 客戶(hù)端繼承框架JFrame,添加各種組件。
2.2 創(chuàng)建客戶(hù)端Socket,設(shè)置請(qǐng)求連接服務(wù)器端IP,以及使用的端口號(hào)。
2.3 封裝客戶(hù)端Socket的getInputStream()函數(shù),獲得客戶(hù)端Socket的輸入流接受服務(wù)器端發(fā)來(lái)的信息,封裝Socket的getOutputStream()函數(shù),獲得Socket的輸出流向服務(wù)器端發(fā)送信息。
2.4 通過(guò)向文本框添加動(dòng)作事件監(jiān)聽(tīng)器,監(jiān)聽(tīng)文本框的輸入。
2.5 當(dāng)與服務(wù)器端連接成功時(shí),系統(tǒng)提醒輸入昵稱(chēng)。系統(tǒng)將對(duì)輸入的昵稱(chēng)進(jìn)行檢索。判斷是否有重復(fù)的昵稱(chēng)。如有重復(fù)則創(chuàng)建不成功,繼續(xù)輸入。
2.6 向服務(wù)器端發(fā)送信息時(shí),如想對(duì)某人發(fā)送私聊信息,則需輸入符合“@私聊對(duì)象的呢稱(chēng):私聊信息”的格式,此時(shí)只有私聊對(duì)象和本人可以接收到。否則,發(fā)送的信息為公聊信息,所有的客戶(hù)端都能夠收到。
2.7 客戶(hù)端不斷接受服務(wù)器端的信息顯示在文本域。

五、代碼說(shuō)話

1、服務(wù)器端:

package server;

import java.io.*; 
import java.net.*; 
import java.util.HashMap; 
import java.util.Map; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.ThreadPoolExecutor; 
import javax.swing.*;
import java.awt.*;

public class TCPServer extends JFrame{  

 private JTextArea m_display=new JTextArea();

 private ServerSocket serverSocket; 

 /** 
 * 創(chuàng)建線程池來(lái)管理客戶(hù)端的連接線程 
 * 避免系統(tǒng)資源過(guò)度浪費(fèi) 
 */ 
 private ExecutorService exec; 

 // 存放客戶(hù)端之間私聊的信息 
 private Map<String,PrintWriter> storeInfo; 

 public TCPServer() { 
  super("聊天程序服務(wù)器端");
  Container c=getContentPane();
  c.add(new JScrollPane(m_display),BorderLayout.CENTER);
  try { 

   serverSocket = new ServerSocket(6666); 
   storeInfo = new HashMap<String, PrintWriter>(); 
   exec = Executors.newCachedThreadPool(); 

  } catch (Exception e) { 
   e.printStackTrace(); 
  } 
 } 

 // 將客戶(hù)端的信息以Map形式存入集合中 
 private void putIn(String key,PrintWriter value) { 
  synchronized(this) { 
   storeInfo.put(key, value); 
  } 
 } 

 // 將給定的輸出流從共享集合中刪除 
 private synchronized void remove(String key) { 
  storeInfo.remove(key); 
  m_display.append("當(dāng)前在線人數(shù)為:"+ storeInfo.size());
  //for(String name: storeInfo.key)
 } 

 // 將給定的消息轉(zhuǎn)發(fā)給所有客戶(hù)端 
 private synchronized void sendToAll(String message) { 
  for(PrintWriter out: storeInfo.values()) { 
   out.println(message); 


   // m_display.append("已經(jīng)發(fā)送了");
  } 
 } 

 // 將給定的消息轉(zhuǎn)發(fā)給私聊的客戶(hù)端 
 private synchronized void sendToSomeone(String name,String message) { 
  PrintWriter pw = storeInfo.get(name); //將對(duì)應(yīng)客戶(hù)端的聊天信息取出作為私聊內(nèi)容發(fā)送出去 
  if(pw != null) pw.println("私聊:  "+message); 
 } 

 public void start() { 
  try { 
   m_display.setVisible(true);
   //m_display.append("mayanshuo");
   while(true) { 

   m_display.append("等待客戶(hù)端連接... ... \n"); 

   Socket socket = serverSocket.accept(); 

   // 獲取客戶(hù)端的ip地址 
   InetAddress address = socket.getInetAddress(); 
   m_display.append("客戶(hù)端:“" + address.getHostAddress() + "”連接成功! "); 
   /* 
   * 啟動(dòng)一個(gè)線程,由線程來(lái)處理客戶(hù)端的請(qǐng)求,這樣可以再次監(jiān)聽(tīng) 
   * 下一個(gè)客戶(hù)端的連接 
   */ 
   exec.execute(new ListenrClient(socket)); //通過(guò)線程池來(lái)分配線程 
   } 
  } catch(Exception e) { 
   e.printStackTrace(); 
  } 
 } 

 /** 
 * 該線程體用來(lái)處理給定的某一個(gè)客戶(hù)端的消息,循環(huán)接收客戶(hù)端發(fā)送 
 * 的每一個(gè)字符串,并輸出到控制臺(tái) 
 */ 
 class ListenrClient implements Runnable { 

  private Socket socket; 
  private String name; 

  public ListenrClient(Socket socket) { 
   this.socket = socket; 
  } 

  // 創(chuàng)建內(nèi)部類(lèi)來(lái)獲取昵稱(chēng) 
  private String getName() throws Exception { 
   try { 
    //服務(wù)端的輸入流讀取客戶(hù)端發(fā)送來(lái)的昵稱(chēng)輸出流 
    BufferedReader bReader = new BufferedReader( 
     new InputStreamReader(socket.getInputStream(), "UTF-8")); 
    //服務(wù)端將昵稱(chēng)驗(yàn)證結(jié)果通過(guò)自身的輸出流發(fā)送給客戶(hù)端 
    PrintWriter ipw = new PrintWriter( 
     new OutputStreamWriter(socket.getOutputStream(), "UTF-8"),true); 

    //讀取客戶(hù)端發(fā)來(lái)的昵稱(chēng) 
    while(true) { 
     String nameString = bReader.readLine(); 
     if ((nameString.trim().length() == 0) || storeInfo.containsKey(nameString)) { 
      ipw.println("FAIL"); 
     } else { 
      ipw.println("OK"); 
      return nameString; 
     } 
    } 
   } catch(Exception e) { 
    throw e; 
   } 
  } 

  @Override   
  public void run() { 
   try { 
    /* 
    * 通過(guò)服務(wù)器端的socket分配給每一個(gè) 
    * 用來(lái)將消息發(fā)送給客戶(hù)端 
    */ 
    PrintWriter pw = new PrintWriter( 
     new OutputStreamWriter(socket.getOutputStream(), "UTF-8"), true); 

    /* 
    * 將客戶(hù)昵稱(chēng)和其所說(shuō)的內(nèi)容存入共享集合HashMap中 
    */ 
    name = getName(); 
    putIn(name, pw); 
    Thread.sleep(100); 

    // 服務(wù)端通知所有客戶(hù)端,某用戶(hù)上線 
    sendToAll("*系統(tǒng)消息* “" + name + "”已上線"); 

    /* 
    * 通過(guò)客戶(hù)端的Socket獲取輸入流 
    * 讀取客戶(hù)端發(fā)送來(lái)的信息 
    */ 
    BufferedReader bReader = new BufferedReader( 
     new InputStreamReader(socket.getInputStream(), "UTF-8")); 
    String msgString = null; 


    while((msgString = bReader.readLine()) != null) { 
     // 檢驗(yàn)是否為私聊(格式:@昵稱(chēng):內(nèi)容) 
     if(msgString.startsWith("@")) { 
      int index = msgString.indexOf(":"); 
      if(index >= 0) { 
       //獲取昵稱(chēng) 
       String theName = msgString.substring(1, index); 
       String info = msgString.substring(index+1, msgString.length()); 
       info = name + ":"+ info; 
       //將私聊信息發(fā)送出去 
       sendToSomeone(theName, info);

       sendToSomeone(name,info);

       continue; 
      } 
     } 
     // 遍歷所有輸出流,將該客戶(hù)端發(fā)送的信息轉(zhuǎn)發(fā)給所有客戶(hù)端 
     m_display.append(name+":"+ msgString+"\n"); 
     sendToAll(name+":"+ msgString); 
    }  
   } catch (Exception e) { 
    // e.printStackTrace(); 
   } finally { 
    remove(name); 
    // 通知所有客戶(hù)端,某某客戶(hù)已經(jīng)下線 
    sendToAll("*系統(tǒng)消息* "+name + "已經(jīng)下線了。\n"); 

    if(socket!=null) { 
     try { 
      socket.close(); 
     } catch(IOException e) { 
      e.printStackTrace(); 
     } 
    }  
   } 
  } 
 } 

 public static void main(String[] args) { 
  TCPServer server = new TCPServer();
  server.setSize(400,400);
  server.setVisible(true);
  server.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  server.start(); 
 } 
} 

2、客戶(hù)端:

package server;

import java.io.*; 
import java.net.*; 
import java.util.Scanner; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.ThreadPoolExecutor; 
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class TCPClient extends JFrame { 

 private JTextField m_enter=new JTextField();
 private JTextArea m_display=new JTextArea();
 private int m_count=0;
 private static Socket clientSocket; 
 //private ExecutorService exec = Executors.newCachedThreadPool(); 
 private BufferedReader br;
 private PrintWriter pw;

 public TCPClient() 
 {
  super("聊天程序客戶(hù)端");


  Container c=getContentPane();
  //m_enter.setSize(100,99);
  //m_display.setSize(200,100);
  m_enter.setVisible(true);
  m_display.setVisible(true);
  m_enter.requestFocusInWindow();  //轉(zhuǎn)移輸入焦點(diǎn)到輸入?yún)^(qū)域

  //將光標(biāo)放置在文本區(qū)域的尾部
  m_display.setCaretPosition(m_display.getText().length());


  c.add(m_enter,BorderLayout.SOUTH);
  c.add(new JScrollPane(m_display),BorderLayout.CENTER); 
  // this.add(panel);
  // this.setContentPane(jp);

 } 


 public static void main(String[] args) throws Exception { 
  TCPClient client = new TCPClient();
  client.setVisible(true);
  client.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  client.setSize(470,708);
  client.start(); 
 } 


 public void start() { 
  try { 
   m_display.append("請(qǐng)創(chuàng)建用戶(hù)名:");
   clientSocket=new Socket("localhost",6666);
   BufferedReader br = new BufferedReader( 
     new InputStreamReader(clientSocket.getInputStream(), "UTF-8")); 
   PrintWriter pw = new PrintWriter( 
     new OutputStreamWriter(clientSocket.getOutputStream(), "UTF-8"), true); 
   //ListenrServser l=new ListenrServser();
   m_enter.addActionListener(new ActionListener(){
    public void actionPerformed(ActionEvent event)
    {
     try{
     String s=event.getActionCommand();
     m_enter.setText("");
      if(m_count==0)
     {
       pw.println(s);
       m_display.append("\n'"+s+"'"+"昵稱(chēng)設(shè)置成功。\n");

     }
     else
     {

       pw.println(s);

     }
     m_count++;

     }catch(Exception e)
     {
      e.printStackTrace();
     }
    }
   });


   String msgString;
   while((msgString = br.readLine())!= null) { 
    m_display.append(msgString+"\n"); 
   } 


  } catch(Exception e) { 
   e.printStackTrace(); 
  } finally { 
   if (clientSocket !=null) { 
    try { 
     clientSocket.close(); 
    } catch(IOException e) { 
     e.printStackTrace(); 
    } 
   } 
  } 
 } 



} 

六、運(yùn)行結(jié)果

1、這里是服務(wù)器端,顯示當(dāng)前連接人數(shù),以及公聊信息:

2、此時(shí)為群內(nèi)成員公聊:

這里創(chuàng)建了三個(gè)角色:馬衍碩、李琦琦、小紅。

 src=

3、私聊:

私聊格式“@名稱(chēng):”+內(nèi)容。
私聊時(shí),只有私聊的兩個(gè)人可以接收到信息,其余人接收不到交流信息。
例:馬衍碩和李琦琦私聊,小紅接收不到私聊信息。
馬衍碩和李琦琦接收到了私聊信息:



小紅沒(méi)有接收到私聊信息:

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Spring 使用xml配置AOP的過(guò)程詳解

    Spring 使用xml配置AOP的過(guò)程詳解

    在之前的學(xué)習(xí)中,都是使用注解的方式進(jìn)行AOP的配置.其實(shí)使用xml配置文件也可以配置AOP,本文給大家分享Spring 使用xml配置AOP的過(guò)程,感興趣的朋友一起看看吧
    2023-11-11
  • SpringBoot實(shí)現(xiàn)子類(lèi)的反序列化示例代碼

    SpringBoot實(shí)現(xiàn)子類(lèi)的反序列化示例代碼

    這篇文章主要給大家介紹了關(guān)于SpringBoot實(shí)現(xiàn)子類(lèi)的反序列化的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用SpringBoot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • Java中mybatis關(guān)于example類(lèi)的使用詳解

    Java中mybatis關(guān)于example類(lèi)的使用詳解

    這篇文章主要介紹了Java中mybatis中關(guān)于example類(lèi)的使用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • java實(shí)現(xiàn)IP地址轉(zhuǎn)換

    java實(shí)現(xiàn)IP地址轉(zhuǎn)換

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)IP地址轉(zhuǎn)換,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • 最長(zhǎng)公共子序列問(wèn)題的深度分析與Java實(shí)現(xiàn)方式

    最長(zhǎng)公共子序列問(wèn)題的深度分析與Java實(shí)現(xiàn)方式

    本文詳細(xì)介紹了最長(zhǎng)公共子序列(LCS)問(wèn)題,包括其概念、暴力解法、動(dòng)態(tài)規(guī)劃解法,并提供了Java代碼實(shí)現(xiàn),暴力解法雖然簡(jiǎn)單,但在大數(shù)據(jù)處理中效率較低,動(dòng)態(tài)規(guī)劃解法通過(guò)構(gòu)建DP表,顯著提高了計(jì)算效率,適用于大規(guī)模數(shù)據(jù)處理
    2025-02-02
  • Java中隊(duì)列Queue和Deque的區(qū)別與代碼實(shí)例

    Java中隊(duì)列Queue和Deque的區(qū)別與代碼實(shí)例

    學(xué)過(guò)數(shù)據(jù)結(jié)構(gòu)的,一定對(duì)隊(duì)列不陌生,java也實(shí)現(xiàn)了隊(duì)列,下面這篇文章主要給大家介紹了關(guān)于Java中隊(duì)列Queue和Deque區(qū)別的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • 分析SpringBoot的啟動(dòng)原理

    分析SpringBoot的啟動(dòng)原理

    這篇文章主要分析了SpringBoot的啟動(dòng)原理,幫助大家更好的理解和使用spring boot框架,感興趣的朋友可以了解下
    2020-09-09
  • Java中List與數(shù)組之間的相互轉(zhuǎn)換

    Java中List與數(shù)組之間的相互轉(zhuǎn)換

    在日常Java學(xué)習(xí)或項(xiàng)目開(kāi)發(fā)中,經(jīng)常會(huì)遇到需要int[]數(shù)組和List列表相互轉(zhuǎn)換的場(chǎng)景,然而往往一時(shí)難以想到有哪些方法,最后可能會(huì)使用暴力逐個(gè)轉(zhuǎn)換法,往往不是我們所滿意的,下面這篇文章主要給大家介紹了關(guān)于Java中List與數(shù)組之間的相互轉(zhuǎn)換,需要的朋友可以參考下
    2023-05-05
  • 一文帶你搞懂Java8的LocalDateTime

    一文帶你搞懂Java8的LocalDateTime

    LocalDateTime?是Java8中新加入的日期時(shí)間類(lèi),現(xiàn)在都?Java20?了,不會(huì)還有人沒(méi)用過(guò)?LocalDateTime?吧?今天給大家演示一下?LocalDateTime?的常用方法
    2023-04-04
  • Java基礎(chǔ)之顏色工具類(lèi)(超詳細(xì)注釋)

    Java基礎(chǔ)之顏色工具類(lèi)(超詳細(xì)注釋)

    這篇文章主要介紹了Java基礎(chǔ)之顏色工具類(lèi)(超詳細(xì)注釋?zhuān)?文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04

最新評(píng)論

平度市| 永德县| 宕昌县| 临颍县| 泸水县| 宁明县| 涞水县| 收藏| 夏津县| 鄱阳县| 威信县| 金山区| 东兴市| 白城市| 迁安市| 德州市| 城步| 周宁县| 宣威市| 南木林县| 义乌市| 高陵县| 宜丰县| 菏泽市| 万荣县| 米泉市| 南京市| 南陵县| 马尔康县| 建宁县| 广南县| 通辽市| 嘉黎县| 盐山县| 来宾市| 应城市| 邢台市| 慈溪市| 博爱县| 阿克苏市| 连江县|