socket编程——局域网聊天

本文介绍了一个简单的局域网多对多聊天系统的实现过程,包括服务器端和客户端的编程,使用了socket编程和TCP/IP协议进行数据传输。系统具备基本的登录功能,并能向所有在线用户广播消息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 这是前段时间写的一个局域网多对多聊天系统,使用socket编程和TCP/IP协议进行数据传输。总体就两个部分,一个是客户端,还有一个是服务器端。其实这个系统编写起来还是很容易的。我这个小程序:

1、有一个登陆界面;

2、登陆之后进入聊天界面后会有一个服务器的欢迎语句。

在这里给出程序的源代码。

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. package org.zsl.server;  
  2.   
  3. //服务器部分  
  4. import java.io.DataInputStream;  
  5.   
  6. import java.io.DataOutputStream;  
  7. import java.io.EOFException;  
  8. import java.io.IOException;  
  9. import java.net.BindException;  
  10. import java.net.ServerSocket;  
  11. import java.net.Socket;  
  12. import java.util.ArrayList;  
  13. import java.util.Date;  
  14. import java.util.List;  
  15. /* 
  16.  * ChatServer类  服务器 
  17.  *  main()          启动程序入口 
  18.  *  start1()        启动服务器,无线循环等待客户端 
  19.  *  
  20.  * ServerThread类            实现了Runnable接口  
  21.  *  ServerThread(Socket s)  构造方法 
  22.  *  send()                  发送数据给客户端 
  23.  *  run()                   覆写方法,接收数据并发送给所有的客户端  
  24.  * */  
  25.   
  26. public class ChatServer {  
  27.   
  28.     private static boolean isRun = false;   //标识符  
  29.   
  30.     private ServerSocket serverSocket = null;       //服务器  
  31.       
  32.     private Socket client = null;  
  33.       
  34.       
  35.     private String name = null;  
  36.       
  37.     List<ServerThread> st = new ArrayList<ServerThread>();      //st集合用来装产生的服务器线程  
  38.       
  39.     public static void main(String[] args) {    //启动方法  
  40.           
  41.         System.out.println("服务器启动!");  
  42.         new ChatServer().start1();  
  43.           
  44.     }  
  45.       
  46.     private void start1() {  
  47.   
  48.         try {  
  49.             serverSocket = new ServerSocket(8888);      //实例化服务器,开启端口  
  50.             isRun = true;                               //改变标识符  
  51.         } catch (BindException e) {  
  52.             System.out.println("端口使用中");  
  53.             System.exit(0);  
  54.         } catch (IOException e) {  
  55.             e.printStackTrace();  
  56.         }  
  57.   
  58.         try {  
  59.   
  60.             while (isRun) {         //无限循环  
  61.   
  62.                 client = serverSocket.accept();     //等待客户端连接,阻塞  
  63.                   
  64.                 ServerThread serverThread = new ServerThread(client);   //一个客户端连接产生了一个服务器的线程  
  65.                   
  66.                   
  67.                   
  68.                 st.add(serverThread);                   //将线程加入结合  
  69.                   
  70.                 name = serverThread.dis.readUTF();  
  71.                   
  72.                 serverThread.setName(name);  
  73.                   
  74.                 new Thread(serverThread).start();       //启动线程  
  75.                   
  76.                 for (int i = 0; i < st.size(); i++) {    //遍历所有的线程  
  77.                       
  78.                     ServerThread temp = st.get(i);  
  79.                       
  80.                     temp.send("<服务器> 欢迎 "+this.name+" 进入聊天室!\n"); //向所有的线程发送信息  
  81.                 }  
  82.                   
  83.                   
  84.                 // dis.close();  
  85.             }  
  86.         } catch (IOException e) {  
  87.             e.printStackTrace();  
  88.         } finally {  
  89.             try {  
  90.                 serverSocket.close();       //关闭服务器  
  91.             } catch (IOException e) {  
  92.                 e.printStackTrace();  
  93.             }  
  94.         }  
  95.     }  
  96.   
  97.     class ServerThread implements Runnable {  
  98.   
  99.         private Socket client;          //定义客户端  
  100.           
  101.         private DataInputStream dis = null;         //定义输入流  
  102.           
  103.         private DataOutputStream dos = null;        //定义输出流  
  104.           
  105.         private boolean bConnected = false;         //定义标志位  
  106.           
  107.         private boolean flag = true;  
  108.           
  109.         private String name = null;     //定义用户姓名  
  110.           
  111.         public String getName() {  
  112.             return name;  
  113.         }  
  114.   
  115.         public void setName(String name) {  
  116.             this.name = name;  
  117.         }  
  118.   
  119.         public ServerThread(Socket s) {  
  120.             this.client = s;  
  121.               
  122.             try {  
  123.                 dis = new DataInputStream(s.getInputStream());      //实例化接收客户端的信息的对象  
  124.                   
  125.                 dos = new DataOutputStream(s.getOutputStream());    //实例化向客户端发送信息对象  
  126.                   
  127.                 bConnected = true;  
  128.                   
  129.             } catch (IOException e) {  
  130.                 e.printStackTrace();  
  131.             }  
  132.   
  133.         }  
  134.   
  135.         public void send(String str) {      //发送信息的方法  
  136.             try {  
  137.                 dos.writeUTF(str);  
  138.             } catch (IOException e) {  
  139.                 st.remove(this);  
  140.   
  141.             }  
  142.         }  
  143.   
  144.         @Override  
  145.         public void run() {  
  146.   
  147.             try {  
  148.                   
  149.                 while (bConnected) {  
  150.                       
  151.                     String str = dis.readUTF();  
  152.                       
  153.                     for (int i = 0; i < st.size(); i++) {    //遍历所有的线程  
  154.                           
  155.                         ServerThread temp = st.get(i);  
  156.                           
  157.                         temp.send("<"+this.name+"  "+new Date()+">\n"+"  "+str);  //向所有的线程发送信息  
  158.                     }  
  159.                       
  160.                 }  
  161.             } catch (EOFException e) {  
  162.                 System.out.println("client closed");  
  163.             } catch (IOException e) {  
  164.                 e.printStackTrace();  
  165.             } finally {  
  166.                 try {  
  167.                     if (client != null) {  
  168.                         client.close();  
  169.                         client = null;  
  170.                     }  
  171.                     if (dis != null)  
  172.                         dis.close();  
  173.                     if (dos != null)  
  174.                         dos.close();  
  175.                 } catch (IOException e1) {  
  176.                     e1.printStackTrace();  
  177.                 }  
  178.   
  179.             }  
  180.   
  181.         }  
  182.   
  183.     }  
  184. }  
[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <pre code_snippet_id="137770" snippet_file_name="blog_20140101_2_5626823" name="code" class="java">package org.zsl.client;  
  2.   
  3.   
  4. import java.awt.Toolkit;  
  5. import java.awt.event.ActionEvent;  
  6. import java.awt.event.ActionListener;  
  7. import java.awt.event.WindowAdapter;  
  8. import java.awt.event.WindowEvent;  
  9.   
  10. import javax.swing.JButton;  
  11. import javax.swing.JFrame;  
  12. import javax.swing.JLabel;  
  13. import javax.swing.JTextField;  
  14.   
  15. //登陆界面  
  16. public class Register {  
  17.     private JFrame frame = new JFrame("聊天系统登陆界面");  
  18.       
  19.     private JLabel lab = new JLabel("请输入姓名:",JLabel.CENTER);  
  20.       
  21.     private JTextField name = new JTextField();  
  22.       
  23.     private JButton submit=new JButton("登陆");  
  24.       
  25.     private JButton reset=new JButton("重置");  
  26.       
  27.     private String c_name = null;  
  28.       
  29.     public String getName(){    //取得用户注册姓名  
  30.         return c_name;  
  31.     }  
  32.       
  33.     public Register(){  
  34.         submit.addActionListener(new ActionListener(){      //采用匿名内部类,注册submit的事件监听  
  35.             public void actionPerformed(ActionEvent arg0){  
  36.                 if(arg0.getSource()==submit){               //判断触发源是否是提交按钮  
  37.                   
  38.                     c_name=name.getText();  
  39.                       
  40.                     new ChatClient(c_name); //将c_name传递到了ChatClient中  
  41.                       
  42.                     frame.dispose();    //关闭本窗口  
  43.                 }  
  44.             }  
  45.         });  
  46.         reset.addActionListener(new ActionListener(){//注册reset的时间监听  
  47.             public void actionPerformed(ActionEvent arg1){  
  48.                 if(arg1.getSource()==reset){//这个按钮没有反应  
  49.                     name.setText("");  
  50.                 }  
  51.             }  
  52.         });  
  53.         frame.addWindowListener(new WindowAdapter(){  
  54.             public void windowClosing(WindowEvent arg0){  
  55.                 System.exit(1);  
  56.             }  
  57.         });  
  58.           
  59.           
  60.         frame.setLayout(null);  
  61.           
  62.         lab.setBounds(255010050);  
  63.         name.setBounds(1356015030);  
  64.         submit.setBounds(751208030);  
  65.         reset.setBounds(1901208030);  
  66.           
  67.           
  68.         frame.add(lab);  
  69.         frame.add(name);  
  70.         frame.add(submit);  
  71.         frame.add(reset);  
  72.           
  73.           
  74.           
  75.         int width = 350;  
  76.         int high = 240;  
  77.         int w = (Toolkit.getDefaultToolkit().getScreenSize().width - width) / 2;  
  78.         int h = (Toolkit.getDefaultToolkit().getScreenSize().height - high) / 2;  
  79.           
  80.         frame.setSize(width, high);  
  81.           
  82.         frame.setLocation(w, h);  
  83.           
  84.         frame.setVisible(true);  
  85.     }  
  86.       
  87.     public static void main(String[] args) {  
  88.         new Register();  
  89.     }  
  90. }  


 
[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. </pre><pre code_snippet_id="137770" snippet_file_name="blog_20140101_4_5943251" name="code" class="java"><pre code_snippet_id="137770" snippet_file_name="blog_20140101_4_5943251" name="code" class="java">package org.zsl.client;  
  2.   
  3. //客户端部分  
  4. import java.awt.Frame;  
  5. import java.awt.TextArea;  
  6. import java.awt.TextField;  
  7. import java.awt.Toolkit;  
  8. import java.awt.event.ActionEvent;  
  9. import java.awt.event.ActionListener;  
  10. import java.awt.event.WindowAdapter;  
  11. import java.awt.event.WindowEvent;  
  12. import java.io.DataInputStream;  
  13. import java.io.DataOutputStream;  
  14. import java.io.EOFException;  
  15. import java.io.IOException;  
  16. import java.net.Socket;  
  17. import java.net.SocketException;  
  18. import java.net.UnknownHostException;  
  19.   
  20. import javax.swing.JButton;  
  21. import javax.swing.JPanel;  
  22.   
  23. public class ChatClient extends Frame {  
  24.   
  25.     Socket socket = null;  
  26.   
  27.     TextField inputChat = new TextField(); // 定义文本框用来输入数据  
  28.   
  29.     TextArea showChat = new TextArea(); // 展示数据的地方  
  30.   
  31.     JButton submit = new JButton("发送");  
  32.   
  33.     JPanel pan = new JPanel();  
  34.   
  35.     DataInputStream dis = null// 接收流  
  36.   
  37.     DataOutputStream dos = null// 输出流  
  38.   
  39.     private String c_name = null;  
  40.   
  41.     private static boolean isRun = false;  
  42.   
  43.     private boolean flag = true// 让c_name的传递只有一次  
  44.   
  45.     public ChatClient() {  
  46.     }  
  47.   
  48.     public static void main(String[] args) {  
  49.         new ChatClient().launchFrame();  
  50.     }  
  51.   
  52.     public ChatClient(String name) {  
  53.         this.c_name = name;  
  54.         this.launchFrame();  
  55.     }  
  56.   
  57.     public void launchFrame() { // Swing 界面  
  58.         this.setTitle("局域网聊天系统");  
  59.   
  60.         int width = 510;  
  61.         int high = 360;  
  62.   
  63.         this.setLayout(null);  
  64.         this.setSize(width, high);  
  65.   
  66.         showChat.setBounds(55490295);  
  67.         pan.setBounds(530549045);  
  68.   
  69.         pan.setLayout(null);  
  70.         inputChat.setBounds(5540040);  
  71.         submit.setBounds(40559540);  
  72.   
  73.         // 居中地位  
  74.         int w = (Toolkit.getDefaultToolkit().getScreenSize().width - width) / 2;  
  75.         int h = (Toolkit.getDefaultToolkit().getScreenSize().height - high) / 2;  
  76.   
  77.         pan.add(inputChat);  
  78.         pan.add(submit);  
  79.   
  80.         this.add(showChat);  
  81.         this.add(pan);  
  82.   
  83.         this.setLocation(w, h);  
  84.   
  85.         this.setVisible(true);  
  86.   
  87.         addWindowListener(new WindowAdapter() {  
  88.             @Override  
  89.             public void windowClosing(WindowEvent e) {  
  90.                 disconnect();  
  91.                 System.exit(0);  
  92.             }  
  93.         });  
  94.           
  95.         inputChat.addActionListener(new TextFieldListener()); // 输入窗口中添加监听  
  96.         submit.addActionListener(new TextFieldListener()); // 输入窗口中添加监听  
  97.   
  98.         connectToServer(); // 连接服务器  
  99.   
  100.         Thread clientThread = new Thread(new ClientThread());  
  101.   
  102.         clientThread.start(); // 启动客户端线程  
  103.     }  
  104.   
  105.     private void connectToServer() {  
  106.         try {  
  107.             socket = new Socket("125.221.225.105"8888);  
  108.   
  109.             dis = new DataInputStream(socket.getInputStream());  
  110.   
  111.             dos = new DataOutputStream(socket.getOutputStream());  
  112.             isRun = true;  
  113.         } catch (UnknownHostException e) {  
  114.             e.printStackTrace();  
  115.         } catch (IOException e) {  
  116.             e.printStackTrace();  
  117.         }  
  118.     }  
  119.   
  120.     public void disconnect() { // 如果没连接上服务器则关闭输入输出流和客户端套接字  
  121.   
  122.         // 关闭各种流之前必须先关闭接受线程  
  123.         try {  
  124.             if (dos != null) {  
  125.                 dos.close();  
  126.             }  
  127.             if (dis != null) {  
  128.                 dis.close();  
  129.             }  
  130.             if (socket != null) {  
  131.                 socket.close();  
  132.             }  
  133.         } catch (IOException e) {  
  134.             e.printStackTrace();  
  135.         }  
  136.     }  
  137.   
  138.     private class ClientThread implements Runnable {  
  139.   
  140.         @Override  
  141.         public void run() {  
  142.   
  143.             try {  
  144.   
  145.                 if (flag) { // 启动客户端只传递一次姓名  
  146.                     dos.writeUTF(c_name);  
  147.                     flag = false;  
  148.                 }  
  149.   
  150.                 while (isRun) { // 无线循环  
  151.   
  152.                     String str = dis.readUTF(); // 取得服务器端发送的消息  
  153.   
  154.                     // System.out.println(str);  
  155.                     // showChat中的部分由以前的 和 现在的组成  
  156.                     showChat.setText(showChat.getText() + str + '\n'); // 在showChat中显示  
  157.   
  158.                 }  
  159.             } catch (SocketException e) {  
  160.                 System.out.println("bye");  
  161.             } catch (EOFException e) {  
  162.   
  163.             } catch (IOException e) {  
  164.                 e.printStackTrace();  
  165.             }  
  166.         }  
  167.   
  168.     }  
  169.   
  170.     private class TextFieldListener implements ActionListener {  
  171.   
  172.         @Override  
  173.         public void actionPerformed(ActionEvent e) {  
  174.             String s = inputChat.getText().trim();  
  175.             if (e.getSource() == submit) {  
  176.                 if(!("".equals(s))){  
  177.                     // showChat.setText(s);  
  178.                     inputChat.setText("");  
  179.                     try {  
  180.                         dos.writeUTF(s);  
  181.                         dos.flush();  
  182.                         // dos.close();  
  183.                     } catch (IOException e1) {  
  184.                         e1.printStackTrace();  
  185.                     }  
  186.                 }  
  187.             } else {  
  188.                 // showChat.setText(s);  
  189.                 inputChat.setText("");  
  190.                 try {  
  191.                     dos.writeUTF(s);  
  192.                     dos.flush();  
  193.                     // dos.close();  
  194.                 } catch (IOException e1) {  
  195.                     e1.printStackTrace();  
  196.                 }  
  197.             }  
  198.   
  199.         }  
  200.   
  201.     }  
  202.   
  203. }  
里面包含聊天室的客户端和服务器端的源文件和一份完整的设计报告。 一、 系统概要 本系统能实现基于VC++的网络聊天室系统。有单独的客户端、服务器端。 服务器应用程序能够接受来自客户端的广播,然后向客户端发送本机的IP与服务端口,让客户端接入到服务器进行聊天,检测用户名是否合法(重复),服务器责接收来自客户端的聊天信息,并根据用户的需求发送给指定的人或所有人,能够给出上线下线提示。客户端能够发出连接请求,能编辑发送信息,可以指定发给单人或所有人,能显示聊天人数,上线下线用户等。 二、 通信规范的制定 服务请求规范: 服务器端: (1) 创建一个UDP的套接字,接受来自客户端的广播请求,当请求报文内容为“REQUEST FOR IP ADDRESS AND SERVERPORT”时,接受请求,给客户端发送本服务器TCP聊天室的端口号。 (2) 创建一个主要的TCP协议的套接字负责客户端TCP连接 ,处理它的连接请求事件。 (3)在主要的TCP连接协议的套接字里面再创建TCP套接字保存到动态数组里,在主要的套接字接受请求后 ,就用这些套接字和客户端发送和接受数据。 客户端: (1) 当用户按“连接”按钮时,创建UDP协议套接字,给本地计算机发广播,广播内容为“REQUEST FOR IP ADDRESS AND SERVERPORT”。 (2)当收到服务器端的回应,收到服务器发来的端口号后,关闭UDP连接。根据服务器的IP地址和端口号重新创建TCP连接。 故我思考:客户端一定要知道服务器的一个端口,我假设它知道服务器UDP服务的端口,通过发广播给服务器的UDP服务套接字,然后等待该套接字发回服务器TCP聊天室服务的端口号,IP地址用ReceiveForom也苛刻得到。 通信规范 通信规范的制定主要跟老师给出的差不多,并做了一小点增加: (增加验证用户名是否与聊天室已有用户重复,在服务器给客户端的消息中,增加标志0) ① TCP/IP数据通信 --- “聊天”消息传输格式 客户机 - 服务器 (1)传输“用户名” STX+1+用户名+ETX (2) 悄悄话 STX+2+用户名+”,”+内容+ETX (3) 对所有人说 STX+3+内容+ETX 服务器- 客户机 (0)请求用户名与在线用户名重复 //改进 STX+0+用户名+EXT (1)首次传输在线用户名 STX+1+用户名+ETX (2)传输新到用户名 STX+2+用户名+ETX (3)传输离线用户名 STX+3+用户名+ETX (4)传输聊天数据 STX+4+内容+ETX (注:STX为CHR(2),ETX 为CHR(3)) 三、 主要模块的设计分析 四、 系统运行效果 (要求有屏幕截图) 五、 心得与体会
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值