一个简单的socket聊天程序

一个简单的Socket聊天程序, 当然是多客户的(客户代码差不多一样),可以添加一些东西,但大概主体是这样的<...>

难点:1.客户端什么时候去读取信息.

   2. 服务器应该怎么存储客户端的每个连接.

对于第一个问题:

  有这样三个回答:

    1.每隔一段时间查看服务器一次

      优点:  可行

      缺点:  有点复杂,这样以来服务器就必须知道客户端哪些已经读取,而哪些内容还没有读取,所以服务器就需要存储信息;

          再者,间隔时间也不好取,太大,延迟高,太小,效率太低.

    2.在用户发送消息时,读取

      有点:  简单

      缺点:  如果有多个客户,这个客户又有点懒,没发送,这样他就接受不到其他用户发送的消息了.

    3.在消息被发送到服务器时,读取

      优点:  效率高

      缺点:  这样必须做一个循环单独来接收消息,但是要放哪里呢(为了防止影响用户与GUI的交互,我们创建一个线程专门监听), GUI启动后,

            除非有事件被触发,否则没有一处是在运转的

第二个问题嘛,我们存储每个客户和服务器连接后的流,因为客户个数未知,故采用自动增长的线性表即可.

下面是代码实现.

 1  1 package jffx.blogs.net;
 2  2 
 3  3 import java.io.*;
 4  4 import java.net.ServerSocket;
 5  5 import java.net.Socket;
 6  6 import java.util.ArrayList;
 7  7 import java.util.Date;
 8  8 
 9  9 //服务器并没有用GUI
10 10 //当然也可以,不过没有必要,
11 11 //一般是写入服务器的配置文件.
12 12 //当然,一切看你
13 13 public class Exercise2_Server {
14 14     /**
15 15      * 保存和服务器连接的每个客户端流
16 16      */
17 17     ArrayList<DataOutputStream> clientOutputStream = null ;
18 18 
19 19 
20 20     public static void main(String[] args) {
21 21         new Exercise2_Server().start() ;
22 22     }
23 23 
24 24     /**
25 25      * 程序主要处理阶段
26 26      */
27 27     private void start() {
28 28         //为存储客户流分配空间
29 29         clientOutputStream = new ArrayList<>() ;
30 30 
31 31         try {
32 32             ServerSocket server = new ServerSocket(4242) ;
33 33 
34 34             //使服务器一直处于监听状态
35 35             while(true) {
36 36                 Socket sock = server.accept() ;
37 37                 DataOutputStream out = new DataOutputStream(
38 38                         new BufferedOutputStream(sock.getOutputStream())
39 39                 ) ;
40 40                 clientOutputStream.add(out) ;
41 41 
42 42                 //处理每个客户
43 43                 new Thread(new ClientHandler(sock)).start() ;
44 44                 //显示消息
45 45                 System.out.println(new Date()) ;
46 46                 System.out.println("	建立一个连接") ;
47 47             }
48 48         } catch (Exception ex) {
49 49             ex.printStackTrace() ;
50 50         }
51 51     }
52 52 
53 53     /**
54 54      * 单独处理每个客户的任务
55 55      */
56 56     private class ClientHandler implements Runnable {
57 57         Socket socket = null ;
58 58         DataInputStream read = null ;
59 59         public ClientHandler(Socket socket) {
60 60             try {
61 61                 this.socket = socket ;
62 62                 read = new DataInputStream(
63 63                         new BufferedInputStream(socket.getInputStream())
64 64                 ) ;
65 65             } catch (Exception ex) {
66 66                 ex.printStackTrace() ;
67 67             }
68 68         }
69 69         @Override
70 70         public void run() {
71 71             String msg ;
72 72             try {
73 73                 //从客户端读取所有消息
74 74                 while((msg = read.readUTF()) != null) {
75 75                     System.out.println("read : " + msg) ;
76 76                     sendToEveryOne(msg) ;   
77 77                 }
78 78             } catch (Exception ex) {
79 79                 ex.printStackTrace() ;
80 80             }
81 81         }
82 82     }
83 83     //发送消息给所有客户
84 84     private void sendToEveryOne(String msg) {
85 85         try {
86 86             for (DataOutputStream writer : clientOutputStream) {
87 87                 writer.writeUTF(msg);
88 88                 writer.flush() ;   //立刻发送输出流
89 89             }
90 90         } catch (Exception ex) {
91 91             ex.printStackTrace() ;
92 92         }
93 93     }
94 94 
95 95 }
Server Code
 1 package jffx.blogs.net;
 2 
 3 import javafx.application.Application;
 4 import javafx.scene.Scene;
 5 import javafx.scene.control.Button;
 6 import javafx.scene.control.ScrollPane;
 7 import javafx.scene.control.TextArea;
 8 import javafx.scene.control.TextField;
 9 import javafx.scene.layout.BorderPane;
10 import javafx.scene.layout.HBox;
11 import javafx.stage.Stage;
12 
13 import java.io.BufferedInputStream;
14 import java.io.BufferedOutputStream;
15 import java.io.DataInputStream;
16 import java.io.DataOutputStream;
17 import java.net.Socket;
18 import java.util.Date;
19 
20 /**
21  * 聊天程序的客户端
22  */
23 public class Exercise2_Client1 extends Application
24 {
25     TextArea ta = new TextArea() ;
26     TextField tf = new TextField() ;
27     DataInputStream in = null ;
28     DataOutputStream out = null ;
29     Socket socket ;
30 
31     @Override
32     public void start(Stage primaryStage) {
33         //画图
34         BorderPane mainPane = new BorderPane() ;
35 
36         mainPane.setCenter(new ScrollPane(ta)) ;
37         ta.setPrefColumnCount(60);
38         ta.setPrefRowCount(80);
39         ta.setEditable(false) ;
40 
41         Button bt = new Button("Send") ;
42         HBox hbox = new HBox(10) ;
43         hbox.getChildren().addAll(tf, bt) ;
44         tf.setPrefColumnCount(50);
45         mainPane.setBottom(hbox);
46 
47         //初始化流
48         setUpNetWorking();
49 
50         //设置GUI事件 -- lambda()
51         bt.setOnAction(event -> {
52             try {
53                 out.writeUTF(tf.getText()) ;
54                 out.flush() ;
55             } catch (Exception ex) {
56                 ex.printStackTrace() ;
57             }
58             //清空文本域
59             tf.setText("");
60         }) ;
61 
62         //创建线程单独处理接收消息
63         //和用户与GUI交互分开
64         Thread readThread = new Thread(() -> {
65             String message ;
66             //反复读取服务器发送的内容
67             try {
68                 while((message = in.readUTF()) != null) {
69                     System.out.println("read : " + ta.getText()) ;
70                     ta.appendText(new Date() + "
");
71                     ta.appendText("	" + message + "
") ;
72                 }
73             } catch (Exception ex) {
74                 ex.printStackTrace() ;
75             }
76         });
77         readThread.start() ;
78 
79         //显示
80         Scene scene = new Scene(mainPane, 400, 600) ;
81         primaryStage.setScene(scene) ;
82         primaryStage.setTitle("Client") ;
83         primaryStage.show() ;
84     }
85     //初始化流
86     private void setUpNetWorking() {
87         try {
88             socket = new Socket("127.0.0.1", 4242) ;
89             in = new DataInputStream(new BufferedInputStream(socket.getInputStream())) ;
90             out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream())) ;
91             System.out.println("时间:" + new Date()) ;
92             System.out.println("	连接建立!") ;
93         } catch (Exception ex) {
94             ex.printStackTrace() ;
95         }
96     }
97 
98 }
Client Code
原文地址:https://www.cnblogs.com/jffx/p/9795593.html