多线程最终服务器和客户端集成一体【swing程序】
我们通过窗体形式来实验这个socket通信。
窗体形式,其实把服务器和客户端集成在一起。因此每个窗体程序既是客户端又是服务器端。
窗体应用程序思路:运行窗体后,此服务器在后台默默监听,而前端展示给客户的是我们所谓的客户端。若服务器接受到相应的消息,则反应在客户端窗体消息窗口中。
首先脑海中窗体形式如下:
为CS新手补习点图形化知识:
Java中使用Awt和Swing类来完成图形化界面。其中Awt是abstract window tookit(抽象窗口工具库),他是最早的gui库。
那为什么会出现swing类呢?他们两者的关联是什么呢?
1.Awt在所有平台上展示的界面很丑陋,功能也有限。
2.Awt是非常笨拙、非面向对象的编程方式。
3.Awt是调用底层平台的GUI实现,因此限制了Awt支持的GUI的实现。
而swing则:
1.开发的图形界面要不awt优秀。
2.采用mvc架构设计,使显示数据与数据来源隔离。
3.是纯java开发,所以在任何平台都展示一样的效果,而不是依赖平台。
他们之间的关联是:swing是在awt的基础上开发出来,现在很少使用awt组件,大部分使用swing组件。
在AWT组件结构:
容器的继承关系如下:
事件关系如下:
还有就是布局管理器组件了。代码中会有相应的解释。
而swing组件关系:
分析我们脑海中的窗体,差不多我们都知道布局。
因为是Tcp协议测试,所以是基于面向链接发送数据。所以在发送之前,首先要连接服务器,若连接上,然后再发送数据。
客户端与服务器消息交流都是在中间的消息框中展示。
在这个窗体中,到底如何布局呢?
这就需要awt的布局管理器。在代码中,我们用的是BorderLayout组件,布局方式是分为东南西北中,若不指定方向,则默认是中间。
BoderLayout效果如下:
在构造器启动服务,服务一直在监听客户端。
若监听到,则开启接受信息的线程,其中线程类作为此主线程类的内部类。
代码如下:并且其中有详细的注释:
package com.test; import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollBar; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; public class SocketTcpDemo1 extends JFrame implements ActionListener { //输入的IP标签 private JLabel ipLable; //输入对方的ip地址 private JTextField sendIp; //连接按钮 private JButton linkBtn; //发送的数据框 private JTextField sendText; //显示数据显示框 private JTextArea showMessage; //创建滚动条 主要是创建垂直滚动条 private JScrollBar verscrollbar; //默认端口号 private int port=30000; //发送按钮 private JButton sendBtn; //默认发送的ip public String defaultSendIp="127.0.0.1"; //连接socket private Socket socket; //构造方法 public SocketTcpDemo1() { this.setTitle("测试tcp通信的窗体"); this.setBounds(200, 200, 500, 500); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setLayout(new BorderLayout()); //定义消息显示数据框 showMessage=new JTextArea(); //设置不可以编辑,消息显示的数据框 showMessage.setEditable(false); //消息显示数据框不够,需要添加滚动条 JScrollPane messageScrollPane=new JScrollPane(showMessage); verscrollbar=messageScrollPane.createVerticalScrollBar(); //把滚动面板放在JFrame容器中 this.add(messageScrollPane, BorderLayout.CENTER); //设置连接ip的数据框 JPanel panel=new JPanel(new BorderLayout(5,2)); //设置发送默认的ip sendIp=new JTextField(defaultSendIp); panel.add(sendIp,BorderLayout.CENTER); //连接按钮 linkBtn=new JButton("连接"); panel.add(linkBtn,BorderLayout.EAST); //ip标签显示 ipLable =new JLabel("对方IP:"); panel.add(ipLable,BorderLayout.WEST); //然后把这个panel放在Frame的上方 this.add(panel,BorderLayout.NORTH); //设置发送数据框的位置 JPanel sendDataPanel=new JPanel(new BorderLayout(5,2)); //发送数据文本框 sendText=new JTextField(); sendDataPanel.add(sendText,BorderLayout.CENTER); //发送按钮 sendBtn=new JButton("发送"); sendDataPanel.add(sendBtn,BorderLayout.EAST); //然后把这个panel放在Frame的下方 this.add(sendDataPanel,BorderLayout.SOUTH); //可视化 this.setVisible(true); //添加事件源 linkBtn.addActionListener(this); sendBtn.addActionListener(this); //启动监听服务方法 TcpServer(); } public void actionPerformed(ActionEvent e) { if(linkBtn==e.getSource()) { //判断是否能连接上 try { socket=new Socket(sendIp.getText().trim(),port); JOptionPane.showMessageDialog(this, "连接成功"); } catch (Exception e1) { try { JOptionPane.showMessageDialog(this, "连接失败"); socket.close(); } catch (IOException e2) { // TODO Auto-generated catch block e2.printStackTrace(); } } } else if(sendBtn==e.getSource()) { try { PrintStream ps=new PrintStream(socket.getOutputStream()); ps.println(sendText.getText()); //显示框中显示 showMessage.append(InetAddress.getLocalHost().getHostAddress()+"说:"+sendText.getText()+"\n"); sendText.setText(""); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } } public static void main(String[] args) { SocketTcpDemo1 tcpSocket=new SocketTcpDemo1(); } //服务监听 private void TcpServer() { try { ServerSocket ss = new ServerSocket(port); while(true) { //此行代码会阻塞,将一直等待别人的连接 Socket s=ss.accept(); new Thread(new ServerThread(s)).start(); } } catch (IOException e) { e.printStackTrace(); } } class ServerThread implements Runnable { //定义当前线程所处理的socket Socket s=null; //该线程所处理的socket所对应的输入流 BufferedReader br=null; public ServerThread(Socket s) { try { this.s=s; //初始化socket对应的输入流 br=new BufferedReader(new InputStreamReader(s.getInputStream())); } catch(IOException e) { e.printStackTrace(); } } @Override public void run() { try { String content = null; while((content = br.readLine()) != null) { //服务器发送的消息 showMessage.append(sendIp.getText().trim()+"说:" + content + "\n"); } } catch (IOException e) { e.printStackTrace(); } } } }
效果如下:
测试连接窗体:
互相通信窗口:
至此,目录中的总结都已经整理完毕。
整理这部分内容的原因:第一:socket通信,当时元旦两天测试出来,可当时遇到点问题,所以索性把练习之旅记录下来。第二:练习基础中的多线程,多线程这部分,基本上理论都可以讲出来,但是项目中一直没有用到。第三:初次接触图形化界面,因为这方面内容没有涉及到,大部分是在研究web方向,但是就像揭开他的神秘面纱。
呵呵,基于以上原因,才有了此次总结的想法。最近一直在研究其他的东西,所以博客没有及时贴出来。(*^__^*)嘻嘻
编译打包成jar包,这部分内容暂时不更新博客了。其实,在打包的过程中应用了ant打包。对于ant的应用,我们有时间再更新博客。