zoukankan      html  css  js  c++  java
  • 一个简单的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
  • 相关阅读:
    论单页Web应用和RESTful架构
    [译]作为一个web开发人员,哪些技术细节是在发布站点前你需要考虑到的
    JavaScript模块化规范
    一个Option请求引发的深度解析
    读《JavaScript语言精粹》的一些感言
    深圳积分入户经验之谈
    windows下的node-canvas历程
    linux服务器部署.net core 3.1
    Windows下Redis的安装、配置
    Linux Centos 安装宝塔面板一句命令解决
  • 原文地址:https://www.cnblogs.com/jffx/p/9795593.html
Copyright © 2011-2022 走看看