国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

香港云服务器
服務器之家 - 編程語言 - Java教程 - Java Socket+多線程實現多人聊天室功能

Java Socket+多線程實現多人聊天室功能

2021-10-11 10:29小剛真的皮 Java教程

這篇文章主要為大家詳細介紹了Java Socket+多線程實現多人聊天室功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

本文實例為大家分享了Java Socket+多線程實現多人聊天室的具體代碼,供大家參考,具體內容如下

思路簡介

分為客戶端和服務器兩個類,所有的客戶端將聊的內容發送給服務器,服務器接受后,將每一條內容發送給每一個客戶端,客戶端再顯示在終端上。

客戶端設計

客戶端包含2個線程,1個用來接受服務器的信息,再顯示,1個用來接收鍵盤的輸入,發送給服務器。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
 
public class WeChatClient {  //WeChat的客戶端類
    private Socket client;
    private String name;
    private InputStream in;
    private OutputStream out;
    private MassageSenter massageSenter;
    private MassageGeter massageGeter;
    class MassageGeter extends Thread{  //一個子線程類,用于客戶端接收消息
        MassageGeter() throws IOException{
            in = client.getInputStream();
        }
        @Override
        public void run() {
            int len;
            byte[] bytes = new byte[1024];
            try {
                while ((len = in.read(bytes)) != -1) { //此函數是阻塞的
                    System.out.println(new String(bytes,0,len, StandardCharsets.UTF_8));
                }
            }catch (IOException e){
                System.out.println(e.toString());
            }
            System.out.println("Connection interruption");
        }
    }
    class MassageSenter extends Thread{  //一個子線程類,用于發送消息給服務器
        MassageSenter() throws IOException{
            out = client.getOutputStream();
        }
 
        @Override
        public void run() {
            Scanner scanner = new Scanner(System.in);
            try {
                while (scanner.hasNextLine()) { //此函數為阻塞的函數
                    String massage = scanner.nextLine();
                    out.write((name + " : " + massage).getBytes(StandardCharsets.UTF_8));
                    if(massage.equals("//exit"))
                        break;
                }
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
 
    WeChatClient(String name, String host, int port) throws IOException {//初始化,實例化發送和接收2個線程
        this.name = name;
        client = new Socket(host,port);
        massageGeter = new MassageGeter();
        massageSenter = new MassageSenter();
 
    }
 
    void login() throws IOException{//登錄時,先發送名字給服務器,在接收到服務器的正確回應之后,啟動線程
        out.write(name.getBytes(StandardCharsets.UTF_8));
        byte[] bytes = new byte[1024];
        int len;
        len = in.read(bytes);
        String answer = new String(bytes,0,len, StandardCharsets.UTF_8);
        if(answer.equals("logined!")) {
            System.out.println("Welcome to WeChat! "+name);
            massageSenter.start();
            massageGeter.start();
            try {
                massageSenter.join();//join()的作用是等線程結束之后再繼續執行主線程(main)
                massageGeter.join();
            }catch (InterruptedException e){
                System.err.println(e.toString());
            }
 
        }else{
            System.out.println("Server Wrong");
        }
        client.close();
    }
 
 
    public static void main(String[] args) throws IOException{//程序入口
        String host = "127.0.0.1";
        WeChatClient client = new WeChatClient("Uzi",host,7777);
        client.login();
    }
 
}

服務器設計

服務器包含3個線程類,端口監聽線程,客戶端接收信息線程,發送信息線程。

服務器類還包含并維護著一個已經連接的用戶列表,和一個待發送信息列表。

服務器有一個負責監聽端口的線程,此線程在接收到客戶端的連接請求后,將連接的客戶端添加進用戶列表;并為每一個連接的客戶端實例化一個接受信息的線程類,從各個客戶端接收員信息,并存入待發送信息列表。

發送信息線程查看列表是否為空,若不為空,則將里面的信息發送給用戶列表的每一個用戶。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
 
public class WeChatServer {
    private ServerSocket server;
    private ArrayList<User> users;//用戶列表
    private ArrayList<String> massages;//待發送消息隊列
    private Listener listener;
    private MassageSenter massageSenter;
 
 
    class User{  //用戶類,包含用戶的登錄id和一個輸出流
        String name;
        OutputStream out;
        User(String name,OutputStream out){
            this.name = name;
            this.out = out;
        }
 
        @Override
        public String toString() {
            return name;
        }
    }
 
    private static String GetMassage(InputStream in) throws IOException{//從一個輸入流接收一個字符串
        int len;
        byte[] bytes = new byte[1024];
        len = in.read(bytes);
        return new String(bytes,0,len,StandardCharsets.UTF_8);
    }
    private void UserList(){  //列出當前在線用戶,調試用
        for(User user : users)
            System.out.println(user);
    }
 
    class Listener extends Thread{ //監聽線程類,負則監聽是否有客戶端連接
        @Override
        public void run() {
            try {
                while (true) {
                    Socket socket = server.accept();//此函數是阻塞的
                    InputStream in = socket.getInputStream();
                    String name = GetMassage(in);//獲取接入用戶的name
                    System.out.println(name +" has connected");
                    massages.add(name+" has joined just now!!");//向聊天室報告用戶連入的信息
                    OutputStream out = socket.getOutputStream();
                    out.write("logined!".getBytes(StandardCharsets.UTF_8));//發送成功建立連接的反饋
                    User user = new User(name,out);
                    users.add(user);//添加至在線用戶列表
                    MassageListener listener = new MassageListener(user,in);//創建用于接收此用戶信息的線程
                    listener.start();
                }
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
    class MassageListener extends Thread{ //接收線程類,用于從一個客戶端接收信息,并加入待發送列表
        private User user;
        private InputStream in;
        MassageListener(User user,InputStream in){
            this.user = user;
            this.in = in;
        }
 
        @Override
        public void run() {
            try {
                while (true){
                    String massage = GetMassage(in);
                    System.out.println("GET MASSAGE  "+massage);
                    if(massage.contains("//exit")){ //       "/exit" 是退出指令
                        break;
                    }
                    massages.add(massage);
                }//用戶退出有兩種形式,輸入 “//exit” 或者直接關閉程序
                in.close();
                user.out.close();
 
            }catch (IOException e){//此異常是處理客戶端異常關閉,即GetMassage(in)調用會拋出異常,因為in出入流已經自動關閉
                e.printStackTrace();
            }finally {
                System.out.println(user.name+" has exited!!");
                massages.add(user.name+" has exited!!");
                users.remove(user);//必須將已經斷開連接的用戶從用戶列表中移除,否則會在發送信息時產生異常
                System.out.println("Now the users has");
                UserList();
            }
 
        }
    }
    private synchronized void SentToAll(String massage)throws IOException{//將信息發送給每一個用戶,加入synchronized修飾,保證在發送時,用戶列表不會被其他線程更改
        if(users.isEmpty())
            return;
        for(User user : users){
            user.out.write(massage.getBytes(StandardCharsets.UTF_8));
        }
    }
 
    class MassageSenter extends Thread{//消息發送線程
 
        @Override
        public void run() {
            while(true){
                try{
                    sleep(1);//此線程中沒有阻塞的函數,加入沉睡語句防止線程過多搶占資源
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
                if(!massages.isEmpty()){
                    String massage = massages.get(0);
                    massages.remove(0);
                    try {
                        SentToAll(massage);
                    }catch (IOException e){
                        e.printStackTrace();
                    }
 
                }
            }
        }
    }
 
    WeChatServer(int port) throws IOException {  //初始化
        server = new ServerSocket(port);
        users = new ArrayList<>();
        massages = new ArrayList<>();
        listener = new Listener();
        massageSenter = new MassageSenter();
    }
 
    private void start(){ //線程啟動
        listener.start();
        massageSenter.start();
    }
 
    public static void main(String[] args) throws IOException{
        WeChatServer server = new WeChatServer(7777);
        server.start();
    }
 
}

總結

之所以需要多線程編程,是因為有的函數是阻塞的,例如

?
1
2
3
while ((len = in.read(bytes)) != -1) { //此函數是阻塞的
    System.out.println(new String(bytes,0,len, StandardCharsets.UTF_8));
}
?
1
2
3
4
5
6
while (scanner.hasNextLine()) { //此函數為阻塞的函數
        String massage = scanner.nextLine();
        out.write((name + " : " + massage).getBytes(StandardCharsets.UTF_8));
        if(massage.equals("//exit"))
     break;
  }
?
1
Socket socket = server.accept();//此函數是阻塞的

這些阻塞的函數是需要等待其他的程序,例如scanner.hasNextLine()需要等待程序員的輸入才會返回值,in.read需要等待流的另一端傳輸數據,使用多線程就可以在這些函數處于阻塞狀態時,去運行其他的線程。

所以,多線程編程的關鍵便是那些阻塞的函數。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:https://blog.csdn.net/qq_40608763/article/details/90755336

延伸 · 閱讀

精彩推薦
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7472021-02-04
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
1236
主站蜘蛛池模板: 色吧网站 | 欧美亚洲综合久久 | 亚洲狠狠爱 | 欧美日韩综合在线 | 日韩av在线免费 | 视频网站免费观看 | 超碰一区二区 | 中文字幕免费观看 | 精品美女久久 | 91视频网页版 | 中文字幕亚洲一区二区三区 | 日韩精品极品视频在线观看免费 | www麻豆| 久久久久国产一区二区三区四区 | 久久久久久久久久久久久久av | 亚洲成人av | 一本大道专区 | 阿v视频在线观看 | 成人黄大片视频在线观看 | 国产福利视频在线观看 | 91福利资源站 | 视频一区在线播放 | 亚洲精品久久久久久久久久久 | 日本久久网 | 综合久久综合 | 国产精品网站在线观看 | 亚洲成人黄色 | 超黄毛片| 狼人综合av | 亚洲精品电影网在线观看 | av电影免费在线观看 | 中文字幕一区二区三区在线视频 | 久久久久一区 | 精品黄色大片 | 99在线精品视频 | 国产一区二区免费视频 | 一级片av| 国产精品美女久久久久久久久久久 | 91福利视频免费 | 亚洲精品无码专区在线播放 | 亚洲欧洲精品一区二区 |