你好,博客园!!第一弹~局域网下的简易聊天室,socket与多线程简结

  发觉博客园里面关于这些基本知识点的详细内容真是应有尽有,所以这里的随笔就不再重复了,就积累一下简单的用法——

  1.Socket

  最近学网络编程,也就是Socket,套接字,一个用来建立链接传输数据的工具。

  数据传输发生在“客户端”与“服务端”之间,下面是一种建立连接传输数据的简单方法:

  (1)客户端

 1 try{
 2     //服务端ip
 3   String ip = "127.0.0.1";
 4   //服务器端口
 5   int port = 5000;
 6
 7   //1.通过服务器ip和端口,创建Socket对象,连接服务器
 8   Socket socket = new Socket(ip, port);
 9   //2.获取Socket输出流,并包装为DataOutputStream
10   DataOutputStream output = new DataOutputStream(socket.getOutputStream());
11   //传输的内容
12   String send = "halo";
13   //3.加密输出,发送到服务端
14     //将一个字符串转换成字符数组
15     char[] char_arr = send.toCharArray();
16     //对每个字符·进行加密操作
17     for(int i=0; i<char_arr.length; i++){
18         output.writeChar(char_arr[i] + 12);
19     }
20     //在输出内容后加一个特殊符号作为结束符
21     output.writeChar(33333);
22     //刷写内容
23     output.flush();
24 } catch (IOException e) {
25     e.printStackTrace();
26 }

  以上为客户端创建连接,发送数据的简单方法。下面是接收数据的方法,注意如果服务端不发送数据过来,代码会停留在字符读取那里。

 1 try{
 2     //4.获取Socket输入流,并包装为DataInputStream
 3     DataInputStream input = new DataInputStream(socket.getInputStream());
 4     //5.获取并解密,接收返回结果
 5     String rtn = "";
 6     while(true) {
 7         //从输出流中读取一个字符,直到结束符
 8         int char_src = input.readChar();
 9         if(char_src != 33333){
10             rtn = rtn + (char)(char_src - 12);
11         }else{
12             break;
13         }
14     }
15     //读取结束,rtn即是服务端发送过来的信息
16 } catch (IOException e) {
17     e.printStackTrace();
18 }

  使用完Socket,一定要关闭Socket及相应的输入输出流。

1 try {2     if(output != null){output.close();}
3     if(input != null){input.close();}
4     if(socket != null){socket.close();}
5 } catch (IOException e) {
6     e.printStackTrace();
7 }

  (1)服务端

  服务端创建连接的方法——

1 //1.创建ServerSocket对象,监听端口5000
2 ServerSocket server_socket = new ServerSocket(5000);
3 //2.调用ServerSocket的accept方法,等待客户端连接(若没有连接,代码停留在这里),成功连接之后,返回Socket对象
4 Socket socket = server_socket.accept();

  创建连接后,数据传输方法跟客户端是同样的步骤,获取Socket的输出输入流并包装,然后加密输出,获取解密,这里不重复了。

  注意这里用了加密传输,所以服务端客户端的加密方法、解密方法一定要一致。用完ServerSocket,也要关闭。

  ******************************************************

  2.多线程

  多线程简单地说,就是为程序建立分支。例如,在聊天室的服务端中,每有一个用户连接进来,就为其建立一个用于接收的分支,这样可以做到同时接受多个用户的数据。

  建立多线程的方法

  

 1 //这是主线程的类,包含主方法
 2 public class text{
 3     public static void main(String [] args){
 4         //new一个thread类,并调用它的start()方法,就建立了一个线程。这步可以重复,不断地建立分支线程
 5         //分支线程建立后,程序一边执行下面的代码,一边执行thread类中的run()方法(分支)
 6         new thread().start();
 7         //继续主线程的其他代码
 8         System.out.println("主线程");
 9     }
10 }
11
12 //thread类必需继承Thread类,这是建立分支线程的关键
13 class thread extends Thread{
14     //需要在分支线程中执行的代码放到run()中
15     public void run(){
16         System.out.println("分支线程");
17     }
18 }

  多线程中各个线程同时运行,其运行没有确定的顺序,并不是先启动的线程一定先执行,当前一刻,谁抢占了 CUP 资源,谁就执行。

  所以上面的程序在cmd中会有不同的执行结果,可能是"主线程"在前面,也可能是"分支线程"在前面。

  多线程还可以通过实现 Runnable 接口来实现,详见聊天室的代码。

************************************************

  

  3.聊天室

  客户端——

  1 import java.awt.*;
  2 import java.awt.event.*;
  3 import javax.swing.*;
  4 import java.io.*;
  5 import java.net.*;
  6
  7 public class chat {
  8
  9     //主方法
 10     public static void main(String[] args) {
 11         chat ch = new chat();
 12         ch.loginframe();
 13
 14     }
 15
 16     //登录窗口
 17     public JFrame lf;
 18     public JTextField lmi;
 19     public JTextField lii;
 20     public int ltz = 1;
 21     public String y;
 22     public void loginframe(){
 23         lf = new JFrame("创建用户");
 24         lf.setVisible(true);
 25         lf.setSize(400, 280);
 26         lf.setLocationRelativeTo(null);
 27         lf.addWindowListener(new WindowAdapter(){
 28             public void windowClosing(WindowEvent e){
 29                 closes();
 30                 System.exit(0);
 31             }
 32         });
 33
 34         JPanel op = new JPanel();
 35         lf.add(op);
 36         Box lbox = Box.createVerticalBox();
 37         op.add(lbox);
 38
 39         lbox.add(Box.createVerticalStrut(40));
 40
 41         JPanel lfp = new JPanel();
 42         lfp.setOpaque(false);
 43         JLabel lft = new JLabel("服务器ip:");
 44         lft.setFont(new Font("华文中宋", Font.PLAIN, 18));
 45         lii = new JTextField("127.0.0.1" ,9);
 46         lii.setFont(new Font("微软雅黑", Font.PLAIN, 18));
 47         lfp.add(lft);
 48         lfp.add(lii);
 49         lbox.add(lfp);
 50
 51         JPanel lip = new JPanel();
 52         lip.setOpaque(false);
 53         JLabel lwt = new JLabel("用户名:");
 54         lwt.setFont(new Font("华文中宋", Font.PLAIN, 18));
 55         lmi = new JTextField(10);
 56         lmi.setFont(new Font("微软雅黑", Font.PLAIN, 18));
 57         lmi.requestFocus();
 58         lip.add(lwt);
 59         lip.add(lmi);
 60         lbox.add(lip);
 61
 62         lbox.add(Box.createVerticalStrut(20));
 63
 64         JPanel obp = new JPanel();
 65         JButton odb = new JButton("加入聊天");
 66         odb.setFont(new Font("微软雅黑", Font.PLAIN, 15));
 67         JLabel obt = new JLabel("    ");
 68         obt.setFont(new Font("华文中宋", Font.PLAIN, 15));
 69         JButton oqb = new JButton("清空输入");
 70         oqb.setFont(new Font("微软雅黑", Font.PLAIN, 15));
 71         obp.add(odb);
 72         obp.add(obt);
 73         obp.add(oqb);
 74         lbox.add(obp);
 75
 76         //按钮监听
 77         odb.addActionListener(new ActionListener(){
 78             public void actionPerformed(ActionEvent e) {
 79                 y = lmi.getText();
 80                 if("".equals(y)){
 81                     JOptionPane.showMessageDialog(null,
 82                             "请输入用户名!", "创建用户", JOptionPane.INFORMATION_MESSAGE);
 83                     lmi.requestFocus();
 84                 }else{
 85                     ip = lii.getText();
 86                     ysend();
 87                     lf.dispose();
 88                     chatframe();
 89                     //开启一条接收信息的线程
 90                     th.start();
 91                 }
 92              }
 93         });
 94
 95         oqb.addActionListener(new ActionListener(){
 96             public void actionPerformed(ActionEvent e) {
 97                 lmi.setText("");
 98              }
 99         });
100
101     }
102
103     //聊天室
104     public JTextField i;
105     public JTextArea l;
106     public String book = "";
107     public void chatframe(){
108         JFrame cf = new JFrame("聊天室 - " + y);
109         cf.setVisible(true);
110         cf.setSize(600, 500);
111         cf.setLocationRelativeTo(null);
112         cf.addWindowListener(new WindowAdapter(){
113             public void windowClosing(WindowEvent e){
114                 closes();
115                 System.exit(0);
116             }
117         });
118
119         JPanel sfp = new JPanel();
120         sfp.setLayout(new BorderLayout());
121         i = new JTextField("请在此输入聊天内容");
122         i.setSelectionStart(0);
123         i.setSelectionEnd(9);
124         i.setFont(new Font("微软雅黑", Font.PLAIN, 20));
125         JButton fsb = new JButton("发 送");
126         fsb.setFont(new Font("微软雅黑", Font.PLAIN, 15));
127         sfp.add(i, BorderLayout.CENTER);
128         sfp.add(fsb, BorderLayout.EAST);
129         cf.add(sfp, BorderLayout.SOUTH);
130
131         l = new JTextArea();
132         l.setFont(new Font("华文中宋", Font.PLAIN, 18));
133         JScrollPane jt = new JScrollPane(l);
134         l.setText(book);
135         cf.add(jt, BorderLayout.CENTER);
136
137         //按钮监听
138         fsb.addActionListener(new ActionListener(){
139             public void actionPerformed(ActionEvent e) {
140                 if("".equals(i.getText())){
141                     i.setText("不能发送空白信息~");
142                     i.setSelectionStart(0);
143                     i.setSelectionEnd(9);
144                     i.requestFocus();
145                 }else{
146                     nsend(i.getText());
147                     i.setText("");
148                     i.requestFocus();
149                 }
150              }
151         });
152
153     }
154     //made by feng(^-^)
155     //创建用户
156     public void ysend(){
157         try {
158             String r;
159             connect();
160             //发送到服务端
161             encryptWrite(y, out);
162             r = readDecrypt(in);
163             book = r;
164             String[] str = r.split("进入聊天室~");
165             if(!(str[0].equals(y))){
166                 JOptionPane.showMessageDialog(null,
167                         "用户“"+y+"”已在聊天室中,系统为你改为"+"“"+str[0]+"”",
168                         "创建用户", JOptionPane.INFORMATION_MESSAGE);
169                 y = str[0];
170             }
171         } catch (IOException e1) {
172             e1.printStackTrace();
173         }
174     }
175
176     //创建socket及相关流
177     public String ip;
178     public int port = 6000;
179     public Socket so;
180     public DataOutputStream out;
181     public DataInputStream in;
182     Thread th = new Thread(new Runc());
183     //连接到服务器
184     public void connect(){
185         try {
186             so = new Socket(ip, port);
187             out = new DataOutputStream(so.getOutputStream());
188             in = new DataInputStream(so.getInputStream());
189         } catch (IOException e) {
190             e.printStackTrace();
191         }
192     }
193
194     //内容传输
195     public void nsend(String n){
196         try {
197             //发送到服务端
198             String s = y + ":" + n;
199             encryptWrite(s, out);
200         } catch (IOException e) {
201             e.printStackTrace();
202         }
203     }
204
205     //关闭流,停止线程运行
206     public boolean bc = true;
207     public void closes(){
208         try {
209             bc = false;
210             //延迟两秒
211             //Thread.sleep(1000 * 2);
212             if(out != null){out.close();}
213             if(in != null){in.close();}
214             if(so != null){so.close();}
215         } catch (IOException e) {
216             e.printStackTrace();
217         }
218     }
219
220     //加密输出
221     public void encryptWrite(String src, DataOutputStream output) throws IOException{
222         char[] char_arr = src.toCharArray();
223         for(int i=0; i<char_arr.length; i++){
224             output.writeChar(char_arr[i] + 12);
225         }
226         output.writeChar(33333);
227         output.flush();
228     }
229
230     //读取解密
231     public String readDecrypt(DataInputStream input) throws IOException{
232         String rtn = "";
233
234         while(true) {
235             //从输出流中读取一个字符,直到结束符
236             int char_src = input.readChar();
237             if(char_src != 33333){
238                 rtn = rtn + (char)(char_src - 12);
239             }else{
240                 break;
241             }
242         }
243         return rtn;
244     }
245
246     /**用于接收消息的线程*/
247     class Runc implements Runnable{
248         public void run(){
249                 try {
250                     while(bc){
251                         String re = readDecrypt(in);
252                         book = book + re;
253                         l.setText(book);
254                     }
255                 } catch (SocketException e) {
256                     //System.out.println("socket关闭,停止接受消息");
257                 } catch (EOFException e) {
258                     //System.out.println("与服务器断开连接");
259                 } catch (IOException e) {
260                     e.printStackTrace();
261                 }
262         }
263     }
264
265 }

  

  服务端——

  1 import java.awt.BorderLayout;
  2 import java.awt.event.*;
  3 import java.io.*;
  4 import java.net.*;
  5 import javax.swing.*;
  6
  7 public class chatserver {
  8     //聊天记录
  9     public static String book = "";
 10     //当前消息
 11     public static String nowm;
 12     //用户名数组
 13     public static String[] name;
 14     //Socket数组
 15     public static Socket[] so;
 16     //每个用户配备一个输出流
 17     public static DataOutputStream[] out;
 18     //用户数量
 19     public static int num = 0;
 20     public static ServerSocket ss = null;
 21     public static Socket s = null;
 22     public static void main(String [] args){
 23         chatserver c = new chatserver();
 24         c.frame();
 25
 26         try {
 27             //监听6000
 28             ss = new ServerSocket(6000);
 29             //初始化用户数组
 30             name = new String[100];
 31             so = new Socket[100];
 32             out = new DataOutputStream[100];
 33             //System.out.println("OK!");
 34             while(true){
 35                 s = ss.accept();
 36                 so[num] = s;
 37                 out[num] = new DataOutputStream(so[num].getOutputStream());
 38                 num++;
 39                 //当有用户接入时,开启一条线程
 40                 new Thread(new Runs(so[num-1])).start();
 41             }
 42         } catch (SocketException e) {
 43             //System.out.println("ss已关闭!");
 44         } catch (IOException e) {
 45             e.printStackTrace();
 46             c.closes();
 47         }
 48     }
 49
 50     //服务器窗口
 51     public JFrame sf;
 52     public static JLabel sl;
 53     public static JLabel rl;
 54     public void frame() {
 55         sf = new JFrame("服务端");
 56         sf.setVisible(true);
 57         sf.setSize(400, 250);
 58         sf.setLocationRelativeTo(null);
 59         sf.addWindowListener(new WindowAdapter(){
 60             public void windowClosing(WindowEvent e){
 61                 closes();
 62                 System.exit(0);
 63             }
 64         });
 65
 66         sl = new JLabel("当前在线人数:"+num);
 67         rl = new JLabel("等待用户接入...");
 68         sf.add(sl, BorderLayout.NORTH);
 69         sf.add(rl, BorderLayout.CENTER);
 70     }
 71     //made by feng(+-+)
 72     //更新窗口显示
 73     public void renew(){
 74         sl.setText("当前在线人数:"+num);
 75         if (num == 0) {
 76             rl.setText("等待用户接入...");
 77         }else{
 78             String s = "";
 79             for (int n = 0; n <= (num - 1); n++) {
 80                 s = s + name[n] + ",";
 81             }
 82             rl.setText("在线用户:"+s);
 83         }
 84     }
 85
 86     //用户接入处理
 87     public synchronized String addh(String y){
 88         int x = 2;
 89         String newy = y;
 90         //检测用户名是否已经存在
 91         for(int n=0; n<(num-1); n++){
 92             if(newy.equals(name[n])){
 93                 //若存在,改为+(n)
 94                 newy = y + " (" +x+ ")";
 95                 x++;
 96                 n = -1;
 97             }
 98         }
 99         name[num-1] = newy;
100         nowm = newy + "进入聊天室~" + "\n";
101         book = book + nowm;
102         renew();
103         sendm();
104         return newy;
105     }
106
107     //信息处理
108     public synchronized void messageh(String n){
109         nowm = n + "\n";
110         book = book + nowm;
111         sendm();
112     }
113
114     //用户断开处理
115     public synchronized void reduceh(String y) {
116         int m = 0;
117         //查找断开连接的用户
118         for(int n=0; n<=(num-1); n++){
119             if(y.equals(name[n])){
120                 m = n;
121                 break;
122             }
123         }
124         //关闭用户的输出流
125         try {
126             out[m].close();
127         } catch (IOException e) {
128             e.printStackTrace();
129         }
130         //数组元素前移
131         for(int n=m; n<=(num-1); n++){
132             name[n] = name[n+1];
133             so[n] = so[n+1];
134             out[n] = out[n+1];
135         }
136         //用户数量减1
137         num--;
138         renew();
139         nowm =  y + "离开聊天室~" + "\n";
140         book = book + nowm;
141         sendm();
142     }
143
144     //消息传输
145     public void sendm(){
146         try {
147             for(int n=0; n<=(num-1); n++){
148                 encryptWrite(nowm, out[n]);
149             }
150         } catch (IOException e) {
151             e.printStackTrace();
152             closes();
153         }
154     }
155
156     //加密输出
157     public void encryptWrite(String src, DataOutputStream output) throws IOException{
158         char[] char_arr = src.toCharArray();
159         for(int i=0; i<char_arr.length; i++){
160             output.writeChar(char_arr[i] + 12);
161         }
162         output.writeChar(33333);
163         output.flush();
164     }
165
166     //关闭socket及流
167     public void closes() {
168         try{
169             for(int n=0; n<=(num-1); n++){
170                 out[n].close();
171             }
172             //System.out.println("outputStream关闭");
173             if(s != null){s.close();}
174             if(ss != null){ss.close();}
175             //System.out.println("s,ss关闭");
176         } catch (IOException e1) {
177             e1.printStackTrace();
178         }
179     }
180 }
181
182 /**接收客户端消息*/
183 class Runs implements Runnable{
184     chatserver cs = new chatserver();
185
186     //创建流
187     public Socket socket;
188     public DataInputStream input;
189     public Runs(Socket s){
190         socket = s;
191         try {
192             input = new DataInputStream(socket.getInputStream());
193         } catch (IOException e) {
194             e.printStackTrace();
195         }
196     }
197
198     public void run(){
199         String n = null;
200         try {
201             //将输入传到主线程并返回用户名
202             n = cs.addh(readDecrypt(input));
203             while(true){
204                 cs.messageh(readDecrypt(input));
205             }
206         } catch (SocketException e) {
207             //System.out.println("socket关闭,停止接受消息");
208         } catch (EOFException e) {
209             //System.out.println("客户端断开,关闭线程");
210             //断开连接后移除用户
211             cs.reduceh(n);
212             //System.out.println(n+"退出成功!");
213         } catch (IOException e) {
214             e.printStackTrace();
215         } finally{
216             try {
217                 if(input != null){ input.close();}
218                 if(socket != null){ socket.close();}
219             } catch (IOException e) {
220                 e.printStackTrace();
221             }
222         }
223     }
224
225     //读取解密
226     public String readDecrypt(DataInputStream input) throws IOException{
227         String rtn = "";
228
229         while(true) {
230             //从输出流中读取一个字符,直到结束符
231             int char_src = input.readChar();
232             if(char_src != 33333){
233                 rtn = rtn + (char)(char_src - 12);
234             }else{
235                 break;
236             }
237         }
238         return rtn;
239     }
240 }

  

  支持多用户,可以在局域网下运行。虽然简单,但也是小弟呕心沥血之作,如果有大佬看见,也希望给点意见啦~

  另外,有人知道怎么上传flsah动画吗,好像这个功能不怎么好使。。

  第一弹就到这里啦~

时间: 2024-08-06 07:56:32

你好,博客园!!第一弹~局域网下的简易聊天室,socket与多线程简结的相关文章

Python - 爬取博客园某一目录下的随笔 - 保存为docx

1 #coding:utf-8 2 import requests 3 from bs4 import BeautifulSoup 4 import MySQLdb 5 6 7 def get_html(url): 8 ''' 9 获取页面HTML源码,并返回 10 ''' 11 html = requests.get(url) 12 content = html.text.encode('utf-8') 13 return content 14 15 def get_blog_html_lis

博客园第一篇———css hover特效

今天看到了一个比较有趣的css hover效果的开源就试做了一下 演示:http://gudh.github.io/ihover/dist/index.html Github Repo在这里:https://github.com/gudh/ihover 文章地址:http://www.html-js.com/topic/274 这是我仿造的他的第一个效果做的,感觉还可以: Start Go! 你即将进入Alfred的个人博客 以下是源码比较简单(至少比自己去分析开源上的源码要简单)就不一一解析了

python学习第一弹:爬虫(抓取博客园新闻)

前言 说到python,对它有点耳闻的人,第一反应可能都是爬虫~ 这两天看了点python的皮毛知识,忍不住想写一个简单的爬虫练练手,JUST DO IT 准备工作 要制作数据抓取的爬虫,对请求的源页面结构需要有特定分析,只有分析正确了,才能更好更快的爬到我们想要的内容. 打开博客园任何一个新闻页面,比如https://news.cnblogs.com/n/570973/,思路是通过这个源页面,并且根据页面中的“上一篇”.“下一篇”等链接,源源不断的爬取其它新闻内容. 浏览器访问https://

我是怎么处理其他网站恶意爬虫博客园的,希望大家喜欢(第二弹)

本文版权归mephisto和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作. 文章是哥(mephisto)写的,SourceLink 阅读目录 介绍 现象 版权处理升级 本文版权归mephisto和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作. 文章是哥(mephisto)写的,SourceLink 介绍 上次写了一篇我是怎么处理其他网站恶意爬虫博客园的,希望大家喜欢,然后大家回复积极,对于我也是一个鼓励,针对上次还有个网站过滤掉了我的版权说明,在这一次却没

如何在博客园没有js执行权限下执行js脚本

前言 小弟刚刚申请的这个博客园博客还比较年轻,没有js执行权限,但是我又想执行js脚本,只好动动歪脑筋. 先从博客园管理中的“页首Html代码”中填写script标签代码,发现保存直接被删除了,又测试了下iframe和frame标签,一样被删除了. 被删除,script标签没有被写入DOM: 解决方案-利用IMG标签的行内事件执行JS 虽然script被删,但是在随后的测试中发现可以添加图片标签. 代码: <img src="http://www.baidu.com/img/baidu_j

博客园,你好

来博客园的第一天,说说感想... 工作一年多了,每次遇到问题时,总是上网搜索看看其他人是否遇到同类型的问题,很幸运的是,大部分问题都能依靠别人的博客或者文章解决.. 我一直很佩服能坚持写博客的人.从技术的角度出发,能将自己工作中遇到的点滴难点及重要技术提炼成条理清晰的文章,这本身就是能力的体现. 即使现在不是技术大佬,将来也是:从品德的角度出发,能将自己的技术及经验无私奉献,让后来者少走弯路,这种开源奉献难道不值得敬佩吗? 这就是我写博客的原始冲动..我会陆续将工作中遇到的难点记录下来.解决不了

Hello World! 你好,博客园!

先说下本文标题,各行各业都有自己的行规和一些内行人玩的梗什么的,这是我开始写技术博客的第一篇,所以它的标题毫无疑问只能是Hello World! 介绍一下我自己 我算是一个少见的科班出身的开发者了,16年毕业于一个普通的211大学计算机科学与技术专业. 科班出身当然不一定要从事程序员,而即使从事程序员这一行业,科班出身也不能让你代码写的更好,或者bug更少.我之所以从事这个行业无非是自认为有点小聪明,也恰好刚接触电脑时,对隐身于网络的大侠黑客有些小崇拜?????,所以义无反顾跳进了这个坑. 14

阿里云MVP携手博客园,寻找下一个MVP!专属服务、大咖交流、企业游学等你来!申请就送100元代金券!

"传递技术力量,传承布道精神."阿里云MVP(最有价值专家)第七期全球招募开启,与博客园携手,寻找热爱技术.乐于分享.关注个人成长的你! 戳链接,通过[博客园绿色通道]一键直达: https://mvp.aliyun.com/mvp/apply?recommendType=2&recommendId=qxJWelDeU8KrQWUUyLKtYw== 前20名申请即提供100元代金券,认证成功还送阿里云T-shirt. 如果你是资深开发者,想第一时间接触最新云技术,实现个人能力跃

分享下我的博客园CSS

今天没事瞎折腾博客园,对于HTML,css,js等 都是了解一点点. 我用的模板是: 修改后的样式为: \ css代码如下: 1 /* Minification failed. Returning unminified contents. 2 (623,18): run-time error CSS1036: Expected expression, found ';' 3 (781,42): run-time error CSS1062: Expected semicolon or closi