欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

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

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

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

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

三、簡單介紹

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

1 服務(wù)器端:

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

2 客戶端:

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

四、設(shè)計描述

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

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

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

(二) 客戶端:

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

五、代碼說話

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)建線程池來管理客戶端的連接線程 
 * 避免系統(tǒng)資源過度浪費 
 */ 
 private ExecutorService exec; 

 // 存放客戶端之間私聊的信息 
 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(); 
  } 
 } 

 // 將客戶端的信息以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ā)給所有客戶端 
 private synchronized void sendToAll(String message) { 
  for(PrintWriter out: storeInfo.values()) { 
   out.println(message); 


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

 // 將給定的消息轉(zhuǎn)發(fā)給私聊的客戶端 
 private synchronized void sendToSomeone(String name,String message) { 
  PrintWriter pw = storeInfo.get(name); //將對應(yīng)客戶端的聊天信息取出作為私聊內(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("等待客戶端連接... ... \n"); 

   Socket socket = serverSocket.accept(); 

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

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

  private Socket socket; 
  private String name; 

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

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

    //讀取客戶端發(fā)來的昵稱 
    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 { 
    /* 
    * 通過服務(wù)器端的socket分配給每一個 
    * 用來將消息發(fā)送給客戶端 
    */ 
    PrintWriter pw = new PrintWriter( 
     new OutputStreamWriter(socket.getOutputStream(), "UTF-8"), true); 

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

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

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


    while((msgString = bReader.readLine()) != null) { 
     // 檢驗是否為私聊(格式:@昵稱:內(nèi)容) 
     if(msgString.startsWith("@")) { 
      int index = msgString.indexOf(":"); 
      if(index >= 0) { 
       //獲取昵稱 
       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; 
      } 
     } 
     // 遍歷所有輸出流,將該客戶端發(fā)送的信息轉(zhuǎn)發(fā)給所有客戶端 
     m_display.append(name+":"+ msgString+"\n"); 
     sendToAll(name+":"+ msgString); 
    }  
   } catch (Exception e) { 
    // e.printStackTrace(); 
   } finally { 
    remove(name); 
    // 通知所有客戶端,某某客戶已經(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、客戶端:

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("聊天程序客戶端");


  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)移輸入焦點到輸入?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("請創(chuàng)建用戶名:");
   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+"'"+"昵稱設(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(); 
    } 
   } 
  } 
 } 



} 

六、運行結(jié)果

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

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

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

 src=

3、私聊:

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



小紅沒有接收到私聊信息:

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

相關(guān)文章

  • Struts之logic標(biāo)簽庫詳解

    Struts之logic標(biāo)簽庫詳解

    本文就Struts之logic標(biāo)簽庫進行詳細(xì)介紹,需要的朋友可以參考下
    2012-11-11
  • Java8 Stream API 詳細(xì)使用方法與操作技巧指南

    Java8 Stream API 詳細(xì)使用方法與操作技巧指南

    這篇文章主要介紹了Java8 Stream API 詳細(xì)使用方法與操作技巧,總結(jié)分析了Java8 Stream API 基本功能、使用方法與操作注意事項,需要的朋友可以參考下
    2020-05-05
  • java實現(xiàn)聯(lián)機五子棋

    java實現(xiàn)聯(lián)機五子棋

    這篇文章主要為大家詳細(xì)介紹了java實現(xiàn)聯(lián)機五子棋,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • Shiro + JWT + SpringBoot應(yīng)用示例代碼詳解

    Shiro + JWT + SpringBoot應(yīng)用示例代碼詳解

    這篇文章主要介紹了Shiro (Shiro + JWT + SpringBoot應(yīng)用),本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-06-06
  • Java多態(tài)實現(xiàn)原理詳細(xì)梳理總結(jié)

    Java多態(tài)實現(xiàn)原理詳細(xì)梳理總結(jié)

    這篇文章主要介紹了Java多態(tài)實現(xiàn)原理詳細(xì)梳理總結(jié),多態(tài)是繼封裝、繼承之后,面向?qū)ο蟮牡谌筇匦裕疚闹豢偨Y(jié)了多態(tài)的實現(xiàn)原理,需要的朋友可以參考一下
    2022-06-06
  • 基于Java數(shù)組實現(xiàn)循環(huán)隊列的兩種方法小結(jié)

    基于Java數(shù)組實現(xiàn)循環(huán)隊列的兩種方法小結(jié)

    下面小編就為大家分享一篇基于Java數(shù)組實現(xiàn)循環(huán)隊列的兩種方法小結(jié),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2017-12-12
  • 解決idea更新maven倉庫的圖文教程

    解決idea更新maven倉庫的圖文教程

    這篇文章主要介紹了解決idea更新maven倉庫的圖文教程,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • spring boot中多線程開發(fā)的注意事項總結(jié)

    spring boot中多線程開發(fā)的注意事項總結(jié)

    spring boot 通過任務(wù)執(zhí)行器 taskexecutor 來實現(xiàn)多線程和并發(fā)編程。下面這篇文章主要給大家介紹了關(guān)于spring boot中多線程開發(fā)的注意事項,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2018-09-09
  • SpringBoot整合UEditor的示例代碼

    SpringBoot整合UEditor的示例代碼

    本篇文章主要介紹了SpringBoot整合UEditor的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-02-02
  • spring中使用@Autowired注解無法注入的情況及解決

    spring中使用@Autowired注解無法注入的情況及解決

    這篇文章主要介紹了spring中使用@Autowired注解無法注入的情況及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09

最新評論