java socket 编程实现网络交谈和同步操作

xiaoxiao2021-02-28  35

java socket 编程实现网络交谈和同步操作


目标

    用java socket编程和多线程机制实现网络交谈和同步操作。

1、程序网络结构图

2、流程图

3、原理

①Java Swing编程

    该网络交谈小程序使用了Java Swing编程技术,实现画图、编辑消息等功能;

②多线程

    该程序使用了多线程技术,在程序运行过程中产生了多个线程。在创建客户端时,为每个客户端开启一个线程,这样客户端之间可以看成是相互独立的。

③Socket编程

    该程序使用了socket编程技术,主进程(即服务器)创建一个服务器端的socket,指定绑定的端口,并监听该端口。当有客户端socket向该端口发送消息时,服务器端接收消息并将该客户端放入一个队列中,该队列中存放当前访问该端口的所有客户端。当服务器向客户端发送消息时,遍历该队列中的所有客户端,同时向所有客户端发送消息。当客户端有消息发送到服务器时,服务器接收该消息,并将该消息转发给客户端队列中的所有客户端,实现消息共享。     注意:     ConnectionException : 对于客户进程, 如果它发出的连接请求被加入到服务器的请求连接队列中, 就意味着客户与服务器的连接建立成功, 客户进程从 Socket 构造方法中正常返回. 如果客户进程发出的连接请求被服务器拒绝, Socket 构造方法就会抛出 ConnectionException.      必须在服务器进程通过 ServerSocket 的 accept() 方法从请求连接队列中取出连接请求, 并返回一个Socket 对象后, 服务器进程这个Socket 对象才与客户端的 Socket 对象形成一条通信线路. 相关博客:http://blog.csdn.net/qq_23473123/article/details/51461894

4、程序的输入与输出

    输入:在“画图”窗口中绘图,在“聊天”窗口中发送消息。     输出:服务器和各客户端同步共享窗口内容。

5、程序运行截图

    a. 如下图所示,运行程序,可看到名为“ycc的通信小程序”的窗口,该窗口包含一个下拉框,一个画图面板和一个聊天面板;

    b. 如下图所示,点击下拉框上的“文件”按钮,弹出“添加客户端”按钮,单击该按钮可添加客户端;

    c. 如下图所示,这里添加了三个客户端,在服务器或任意客户端上画图,其它窗口可同步显示该图片;

    d. 如下图所示,点击“聊天”面板,在服务器或任意客户端窗口的编辑框中编辑消息并点击发送按钮,其它窗口均可显示该消息;

6、代码实现

①程序结构

②客户端Client.java

package networkTalk; import java.awt.BorderLayout; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.Socket; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; import javax.swing.JTextArea; import javax.swing.JTextField; import networkTalk.Client; public class Client extends JFrame{ public JTextArea area; //聊天窗口的输入框 JTextField field; //聊天窗口的显示框 JButton button; //这里不能用static,每个客户端必须是独立的 public PrintWriter writer; public Graphics g; //用来画图的面板 public JPanel contentPanel1; public Client() { //使用java swing的一些控件 this.setTitle("客户端"); this.setSize(500, 500); JMenu jMenu = new JMenu("文件"); //菜单对象 JMenuItem t = new JMenuItem("添加客户端");//菜单项 jMenu.add(t); JMenuBar jMenuBar = new JMenuBar(); //创建菜单工具栏 jMenuBar.add(jMenu); this.setJMenuBar(jMenuBar); JTabbedPane jTabbedPane = new JTabbedPane(JTabbedPane.LEFT);//设置选项卡坐标 contentPanel1 = new JPanel();//创建多个容器 JPanel contentPanel2 = new JPanel(); jTabbedPane.add("画图",contentPanel1); jTabbedPane.add("聊天",contentPanel2); this.add(jTabbedPane,BorderLayout.CENTER); area= new JTextArea(20,30); field = new JTextField(20); button=new JButton("提交"); JScrollPane sp =new JScrollPane(area); contentPanel2.add(sp,BorderLayout.CENTER); contentPanel2.add(field); contentPanel2.add(button); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //聊天界面中消息发送按钮的监听事件 button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { //获取编辑框中的内容 String text = field.getText(); //输出流,传递给服务器 writer.println(text); //显示框中显示内容 area.append("我:"+text+"\n"); //编辑设为空 field.setText(""); } }); //“添加客户端”按钮的监听事件,点击该按钮添加一个客户端 t.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { // TODO Auto-generated method stub Runnable myRunnable = new Runnable(){ @Override public void run() { // TODO Auto-generated method stub try { Client.main(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; Thread thread = new Thread(myRunnable); thread.start(); } }); //在画图面板中监听鼠标消息 contentPanel1.addMouseMotionListener(new MouseMotionListener() { int x=0; int y=0; @Override public void mouseMoved(MouseEvent e) { // TODO Auto-generated method stub } @Override public void mouseDragged(MouseEvent e) { // TODO Auto-generated method stub // 获取鼠标坐标 x = e.getX(); y = e.getY(); //将消息传给服务器 writer.println(x + "*" + y); g = contentPanel1.getGraphics(); //这里也用到了 g.fillOval(x, y, 1, 1); } }); } public static void main() throws Exception{ Client c =new Client(); //创建客户端socket,指定服务器地址和端口 Socket socket =new Socket("127.0.0.1",9995); //获取输出流,向服务器发送消息 OutputStream out = socket.getOutputStream(); //输出流 c.writer=new PrintWriter(out,true); //将输出流包装成打印流 System.out.println("成功连接服务器!"); //获取输入流,并读取服务器端的响应信息 BufferedReader reader=new BufferedReader(new InputStreamReader(socket.getInputStream())); while(true){ //获取客户端消息 String line = reader.readLine(); String a[] = new String[2]; //画图时传回来的值是x*y,调用split方法后a的长度为2,聊天时没有*符号,a的长度为1 a = line.split("\\*"); if(a.length == 1){ //聊天 c.area.append("客户端:"+a[0]+"\n"); }else { //画图 int x = Integer.parseInt(a[0]); int y = Integer.parseInt(a[1]); c.g = c.contentPanel1.getGraphics(); c.g.fillOval(x, y, 1, 1); } } } }

①服务器端Server.java

package networkTalk; import java.awt.BorderLayout; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; 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 java.util.ArrayList; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; import javax.swing.JTextArea; import javax.swing.JTextField; import networkTalk.Server; public class Server extends JFrame{ static JTextArea area; //聊天窗口的输入框 JTextField field; //聊天窗口的显示框 JButton button; static PrintStream writer; //打印流,设置为全局变量 static Graphics g; //画图 static JPanel contentPanel1; //用来画图的面板 static ArrayList<Socket> sList; //socket请求队列 public Server(){ //使用java swing的一些控件 this.setTitle("ycc的通信小程序"); this.setSize(500,500); JMenu jMenu = new JMenu("文件"); //菜单对象 JMenuItem t = new JMenuItem("添加客户端"); jMenu.add(t); JMenuBar jMenuBar = new JMenuBar(); //创建菜单工具栏 jMenuBar.add(jMenu); this.setJMenuBar(jMenuBar); JTabbedPane jTabbedPane = new JTabbedPane(JTabbedPane.LEFT);//设置选项卡坐标 contentPanel1 = new JPanel(); //创建多个容器 JPanel contentPanel2 = new JPanel(); jTabbedPane.add("画图",contentPanel1); jTabbedPane.add("聊天",contentPanel2); this.add(jTabbedPane,BorderLayout.CENTER); area = new JTextArea(20,30); area.setEditable(false); field = new JTextField(20); button = new JButton("提交"); JScrollPane sp = new JScrollPane(area); contentPanel2.add(sp,BorderLayout.CENTER); contentPanel2.add(field); contentPanel2.add(button); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //在画图面板中监听鼠标消息 contentPanel1.addMouseMotionListener(new MouseMotionListener() { //X,Y表示鼠标当前坐标 int x=0; int y=0; @Override public void mouseMoved(MouseEvent e) { // TODO Auto-generated method stub } @Override public void mouseDragged(MouseEvent e) { // 获取鼠标坐标 x = e.getX(); y = e.getY(); //writer.println(x + "*" + y); //将消息广播给各个客户端 for (Socket s : sList) { try { //System.out.println(s); PrintStream writer1; //获取输出流 writer1 = new PrintStream(s.getOutputStream(),true); //传给客户端 writer1.println(x + "*" + y); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } //调用graphics画图 g = contentPanel1.getGraphics(); g.fillOval(x, y, 1, 1); } }); //“添加客户端”按钮的监听事件,点击该按钮添加一个客户端 t.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { //为客户端开启一个线程 Runnable myRunnable = new Runnable(){ @Override public void run() { // TODO Auto-generated method stub try { Client.main(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; //启动线程 Thread thread = new Thread(myRunnable); thread.start(); } }); //聊天界面中消息发送按钮的监听事件 button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String text =field.getText(); // writer.println(text); //广播 for (Socket s : sList) { try { System.out.println(s); PrintStream writer1; writer1 = new PrintStream(s.getOutputStream(),true); writer1.println(text); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } area.append("我:"+text+"\n"); field.setText(""); } }); } /*=================================================================================*/ public static void main(String[] args) throws Exception{ Server s = new Server(); //创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口 ServerSocket server =new ServerSocket(9995); System.out.println("服务端准备完毕!开始监听请求!"); Server.sList = new ArrayList<Socket>(); for(;;) { //调用accept()方法开始监听,等待客户端的连接 Socket socket = server.accept(); //这个socket传给下面开启的线程 //这里接收到的socket要在下面开启的线程中用到 //添加到socket队列中 sList.add(socket); //开启多线程 class MyThread implements Runnable { private Socket m_Socket; public void setSocket(Socket s) { m_Socket = s; } @Override public void run() { // TODO Auto-generated method stub try { //下面的代码放到一个单独的线程中,每次accept到新的socke都开一个线程 InetAddress address =m_Socket.getInetAddress(); String name = address.getLocalHost().getHostName(); System.out.println(name+"已成功连接"); //getOutputStream方法使连接的另一端得到输入 writer=new PrintStream(m_Socket.getOutputStream(),true); //获取从客户端传回来的值 BufferedReader reader = new BufferedReader(new InputStreamReader(m_Socket.getInputStream())); while(true){ String line=null; line=reader.readLine(); String a[] = new String[2]; //画图时传回来的值是x*y,调用split方法后a的长度为2,聊天时没有*符号,a的长度为1 a = line.split("\\*"); //收到的数据发送给slist里面的其它客户端,广播 for (Socket s : sList) { System.out.println(s); if (m_Socket != s) { PrintStream writer1;//新的 writer,发给其他客户端 writer1 = new PrintStream(s.getOutputStream(),true); writer1.println(line); } } if(a.length == 1){ //聊天 area.append("客户端:"+a[0]+"\n"); }else { //画图 int x = Integer.parseInt(a[0]); int y = Integer.parseInt(a[1]); g = contentPanel1.getGraphics(); g.fillOval(x, y, 1, 1); } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } MyThread myRunnable = new MyThread(); myRunnable.setSocket(socket); Thread thread = new Thread(myRunnable); thread.start(); } } }
转载请注明原文地址: https://www.6miu.com/read-2150155.html

最新回复(0)