通信软件基础B-重庆邮电大学-Java-编程实现一个简单的聊天程序-多线程编程实现

实验任务六

编程实现一个简单的聊天程序-多线程编程实现

1、 系统设计要求

编程实现一个简单的聊天程序,实现两台计算机间的信息交互,使用多线程编程实现;可同时连接多个客户端,服务器收到客户端发送的消息后转发给所有连接到服务器的客户端。客户端可以随时随地的发送信息。

2、 设计思路与方案

1) 设计思路
① 客户端设计思路:

  1. 设计好客户端的界面,包括待发送的消息的文本框,以及可以点击发送的发送消息按钮,以及接收消息的文本区域。
  2. 创建Socket套接字,配置好地址与端口号,实例化向服务器写的字节流以及实例化向服务器的字节流。
  3. 创建线程:在线程中对服务器转发的字节流进行监听,每监测到一行数据便将这行数据显示到接收消息的文本区域。
  4. 每次点击发送按钮时,读取输入区的文字并将其发送至服务器,发送的数据格式为用户名+消息条数目+“:”+消息具体内容。
    ② 服务器设计思路:
  5. 因为每一个客户端实例都需要与服务器建立向服务器的写字节流,故每登录一个新的客户端时则都会建立起一个新的线程,用以建立向服务器的写字节流以及监听每一个客户端是否有消息发送。
  6. 采用方法是服务器端每接收到一个新的客户端链接请求时便创建一个新的客户端对象,在每一个客户端对象中都有一个线程用于建立向服务器的写字节流以及监听每一个客户端是否有消息发送。
  7. 一旦监听到其中一个或多个客户端发送消息时,服务器端读取到发送的内容并将其转发给所有的已连接上服务器的客户端。
  8. 因为需要转发给所有的客户端对象,故在创建新的客户端对象是,会将该新的客户端对象存储在一个ArrayList集合中,在读取到消息时,遍历该集合中的所有客户端然后分别向其发送收到的内容。
    2) 程序总体框图
    在这里插入图片描述
    3) 程序算法模块
    ① 客户端:
    1.建立链接:
    public void startUp(String name){
        userName=name;
        try{
            Socket sock=new Socket("127.0.0.1",4242);
            out=new ObjectOutputStream(sock.getOutputStream());
            in =new ObjectInputStream(sock.getInputStream());
            Thread remote=new Thread(new RemoteReader());
            remote.start();
        }catch(Exception ex){
            System.out.println("couldn`t connect-you`ll have to play alone.");
        }
        setUpMidi();
        buildGUI();
        
        
    }

2.建立客户端界面:

    public void buildGUI(){
        theFrame=new JFrame("Cyber BeatBox");
        BorderLayout layout=new BorderLayout();
        theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel background=new JPanel(layout);
        background.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));

        
        checkboxList=new ArrayList<JCheckBox>();
        Box buttonBox=new Box(BoxLayout.Y_AXIS);

        JButton start=new JButton("Start");
        start.addActionListener(new MyStarListener());
        buttonBox.add(start);

        JButton stop=new JButton("Stop");
        stop.addActionListener(new MyStopListener());
        buttonBox.add(stop);

        JButton upTempo=new JButton("Tempo Up");
        upTempo.addActionListener(new MyUpTempoListener());
        buttonBox.add(upTempo);

        JButton downTempo=new JButton("Tempo down");
        downTempo.addActionListener(new MyDownTempoListener());
        buttonBox.add(downTempo);

        JButton sendIt=new JButton("sendIt");
        sendIt.addActionListener(new MySendListener());
        buttonBox.add(sendIt);

        userMessage=new JTextField();
        buttonBox.add(userMessage);

        incomingList=new JList();
        incomingList.addListSelectionListener(new MyListSelectionListener());
        incomingList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        JScrollPane theList=new JScrollPane(incomingList);
        buttonBox.add(theList);
        incomingList.setListData(listVector);

        Box nameBox=new Box(BoxLayout.Y_AXIS);
        for(int i=0;i<16;i++){
            nameBox.add(new Label(instrumentNames[i]));
        }

        background.add(BorderLayout.EAST,buttonBox);
        background.add(BorderLayout.WEST,nameBox);

        theFrame.getContentPane().add(background);

        GridLayout grid=new GridLayout(16,16);
        grid.setVgap(1);
        grid.setHgap(2);
        mainPanel=new JPanel(grid);
        background.add(BorderLayout.CENTER,mainPanel);

        for(int i=0;i<256;i++){
            JCheckBox c=new JCheckBox();
            c.setSelected(false);
            checkboxList.add(c);
            mainPanel.add(c);
        }


        theFrame.setBounds(50,50,300,300);
        theFrame.pack();
        theFrame.setVisible(true);
    }

3.客户端线程:

    public class RemoteReader implements Runnable{
        boolean[] checkboxState=null;
        String nameToShow=null;
        Object obj=null;
        public void run(){
            try{
                while((obj=in.readObject())!=null){
                    System.out.println("got an object from server");
                    System.out.println(obj.getClass());
                    String nameToShow=(String) obj;
                    checkboxState=(boolean[]) in.readObject();
                    
                    otherSeqsMap.put(nameToShow,checkboxState);
                    listVector.add(nameToShow);
                    incomingList.setListData(listVector);
                }
            }catch(Exception ex){
                ex.printStackTrace();
            }
        }
    }

4.监听发送按钮:

    public class MySendListener implements ActionListener{
        public void actionPerformed(ActionEvent a){
            boolean[] checkboxState=new boolean[256];
            for(int i=0;i<256;i++){
                JCheckBox check=(JCheckBox) checkboxList.get(i);
                if(check.isSelected()){
                    checkboxState[i]=true;
                }
            }
            String messageToSend=null;
            try{
                out.writeObject(userName+ nextNum++ +": " + userMessage.getText());
                out.writeObject(checkboxState);
            }catch(Exception ex){
                System.out.println("Sorry dude. Could not send it to the server.");
            }
            userMessage.setText("");
        }
    }

② 服务器:
1.建立某个客户端链接:

    public void go(){
        clientOutputStreams=new ArrayList<ObjectOutputStream>();

        try{
            ServerSocket serversock=new ServerSocket(4242);

            while(true){
                Socket clientSocket=serversock.accept();
                ObjectOutputStream out=new ObjectOutputStream(clientSocket.getOutputStream());
                clientOutputStreams.add(out);

                Thread t=new Thread(new ClientHandler(clientSocket));
                t.start();

                System.out.println("got a connection");
            }
        }catch(Exception ex){
            ex.printStackTrace();
        }
    }

2.客户端内部类(包含线程):

    public class ClientHandler implements Runnable{
        ObjectInputStream in;
        Socket clientSocket;
        
        public ClientHandler(Socket socket){
            try{
                clientSocket=socket;
                in= new ObjectInputStream(clientSocket.getInputStream());
            }catch(Exception ex){
                ex.printStackTrace();
            }
        }

        public void run(){
            Object o2=null;
            Object o1=null;
            try{

                while((o1=in.readObject())!=null){
                    o2=in.readObject();

                    System.out.println("read two objects");
                    tellEveryone(o1,o2);
                }
            }catch(Exception ex){ex.printStackTrace();}
        }
    }
3.运行结果示例

聊天结果示例1:
在这里插入图片描述
聊天结果示例2:
在这里插入图片描述
服务器响应:
在这里插入图片描述

4.完整代码

客户端(客户端运行时需输入字符串参数,如:“xx同学”):

import java.awt.*;
import javax.swing.*;
import java.io.*;
import javax.sound.midi.*;
import java.util.*;
import java.awt.event.*;
import java.net.*;
import javax.swing.event.*;
import javax.swing.Box;


public class BeatBoxFinal{
    JFrame theFrame;
    JPanel mainPanel;
    JList incomingList;
    JTextField userMessage;
    ArrayList<JCheckBox> checkboxList;
    int nextNum;
    Vector<String> listVector=new Vector<String>();
    String userName;
    ObjectOutputStream out;
    ObjectInputStream in;
    HashMap<String,boolean[]> otherSeqsMap=new HashMap<String,boolean[]>();

    Sequencer sequencer;
    Sequence sequence;
    Sequence mySequence=null;
    Track track;
    

    String[] instrumentNames={"Bass Drum","Closed Hi-Hat","Open Hi-Hat","Acoustic Snare","Crash Cymbal","Hand Clap","High Tom","Hi Bongo","Maracas","Whistle","Low Conga","Cowbell","Vibraslap","Low-mid Tom","High Agogo","Open Hi Conga"};
    int[] instruments={35,42,46,38,49,39,50,60,70,72,64,56,58,47,67,63};

    public static void main(String[] args){
        new BeatBoxFinal().startUp(args[0]);
    }
    
    public void startUp(String name){
        userName=name;
        try{
            Socket sock=new Socket("127.0.0.1",4242);
            out=new ObjectOutputStream(sock.getOutputStream());
            in =new ObjectInputStream(sock.getInputStream());
            Thread remote=new Thread(new RemoteReader());
            remote.start();
        }catch(Exception ex){
            System.out.println("couldn`t connect-you`ll have to play alone.");
        }
        setUpMidi();
        buildGUI();
        
        
    }
    public void buildGUI(){
        theFrame=new JFrame("Cyber BeatBox");
        BorderLayout layout=new BorderLayout();
        theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel background=new JPanel(layout);
        background.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));

        
        checkboxList=new ArrayList<JCheckBox>();
        Box buttonBox=new Box(BoxLayout.Y_AXIS);

        JButton start=new JButton("Start");
        start.addActionListener(new MyStarListener());
        buttonBox.add(start);

        JButton stop=new JButton("Stop");
        stop.addActionListener(new MyStopListener());
        buttonBox.add(stop);

        JButton upTempo=new JButton("Tempo Up");
        upTempo.addActionListener(new MyUpTempoListener());
        buttonBox.add(upTempo);

        JButton downTempo=new JButton("Tempo down");
        downTempo.addActionListener(new MyDownTempoListener());
        buttonBox.add(downTempo);

        JButton sendIt=new JButton("sendIt");
        sendIt.addActionListener(new MySendListener());
        buttonBox.add(sendIt);

        userMessage=new JTextField();
        buttonBox.add(userMessage);

        incomingList=new JList();
        incomingList.addListSelectionListener(new MyListSelectionListener());
        incomingList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        JScrollPane theList=new JScrollPane(incomingList);
        buttonBox.add(theList);
        incomingList.setListData(listVector);

        Box nameBox=new Box(BoxLayout.Y_AXIS);
        for(int i=0;i<16;i++){
            nameBox.add(new Label(instrumentNames[i]));
        }

        background.add(BorderLayout.EAST,buttonBox);
        background.add(BorderLayout.WEST,nameBox);

        theFrame.getContentPane().add(background);

        GridLayout grid=new GridLayout(16,16);
        grid.setVgap(1);
        grid.setHgap(2);
        mainPanel=new JPanel(grid);
        background.add(BorderLayout.CENTER,mainPanel);

        for(int i=0;i<256;i++){
            JCheckBox c=new JCheckBox();
            c.setSelected(false);
            checkboxList.add(c);
            mainPanel.add(c);
        }


        theFrame.setBounds(50,50,300,300);
        theFrame.pack();
        theFrame.setVisible(true);
    }

    public void setUpMidi(){
        try{
            sequencer=MidiSystem.getSequencer();
            sequencer.open();
            sequence=new Sequence(Sequence.PPQ,4);
            track=sequence.createTrack();
            sequencer.setTempoInBPM(120);
        }catch(Exception e){
            e.printStackTrace();
        }
    }

    public void buildTrackAndStart(){
        ArrayList<Integer> trackList=null;

        sequence.deleteTrack(track);
        track=sequence.createTrack();

        for(int i=0;i<16;i++){
            trackList=new ArrayList<Integer>();

            for(int j=0;j<16;j++){
                JCheckBox jc=(JCheckBox) checkboxList.get(j+(16*i));
                if(jc.isSelected()){
                    int key=instruments[i];
                    trackList.add(new Integer(key));
                }else{
                    trackList.add(null);
                }
            }

            makeTracks(trackList);
        }

        track.add(makeEvent(192,9,1,0,15));
        try{

            sequencer.setSequence(sequence);
            sequencer.setLoopCount(sequencer.LOOP_CONTINUOUSLY);
            sequencer.start();
            sequencer.setTempoInBPM(120);
        }catch(Exception e){
            e.printStackTrace();
        }
    }

    public class MyStarListener implements ActionListener{
        public void actionPerformed(ActionEvent a){
            buildTrackAndStart();
        }
    }

    public class MyStopListener implements ActionListener{
        public void actionPerformed(ActionEvent a){
            sequencer.stop();
        }
    }

    public class MyUpTempoListener implements ActionListener{
        public void actionPerformed(ActionEvent a){
            float tempoFactor=sequencer.getTempoFactor();
            sequencer.setTempoFactor((float)(tempoFactor*1.03));
        }
    }

    public class MyDownTempoListener implements ActionListener{
        public void actionPerformed(ActionEvent a){
            float tempoFactor=sequencer.getTempoFactor();
            sequencer.setTempoFactor((float)(tempoFactor*0.97));
        }
    }

    public class MySendListener implements ActionListener{
        public void actionPerformed(ActionEvent a){
            boolean[] checkboxState=new boolean[256];
            for(int i=0;i<256;i++){
                JCheckBox check=(JCheckBox) checkboxList.get(i);
                if(check.isSelected()){
                    checkboxState[i]=true;
                }
            }
            String messageToSend=null;
            try{
                out.writeObject(userName+ nextNum++ +": " + userMessage.getText());
                out.writeObject(checkboxState);
            }catch(Exception ex){
                System.out.println("Sorry dude. Could not send it to the server.");
            }
            userMessage.setText("");
        }
    }
    public class MyListSelectionListener implements ListSelectionListener{
        public void valueChanged(ListSelectionEvent le){
            if(le.getValueIsAdjusting()){
                String selected=(String) incomingList.getSelectedValue();
                if(selected!=null){
                    boolean[] selectedState=(boolean[]) otherSeqsMap.get(selected);
                    changeSequence(selectedState);
                    sequencer.stop();
                    buildTrackAndStart();
                }
            }
        }
    }
    public class RemoteReader implements Runnable{
        boolean[] checkboxState=null;
        String nameToShow=null;
        Object obj=null;
        public void run(){
            try{
                while((obj=in.readObject())!=null){
                    System.out.println("got an object from server");
                    System.out.println(obj.getClass());
                    String nameToShow=(String) obj;
                    checkboxState=(boolean[]) in.readObject();
                    
                    otherSeqsMap.put(nameToShow,checkboxState);
                    listVector.add(nameToShow);
                    incomingList.setListData(listVector);
                }
            }catch(Exception ex){
                ex.printStackTrace();
            }
        }
    }
    public class MyPlayMineListener implements ActionListener{
        public void actionPerformed(ActionEvent a){
            if(mySequence!=null){
                sequence=mySequence;
            }
        }
    }
    public void changeSequence(boolean[] checkboxState){
        for(int i=0;i<256;i++){
            JCheckBox check=(JCheckBox) checkboxList.get(i);
            if(checkboxState[i]){
                check.setSelected(true);
            }else{
                check.setSelected(false);
            }
        }
    }
    public void makeTracks(ArrayList list){
        Iterator it=list.iterator();
        for(int i=0;i<16;i++){
            Integer num=(Integer) it.next();
            if(num!=null){
                int numKey=num.intValue();
                track.add(makeEvent(144,9,numKey,100,i));
                track.add(makeEvent(128,9,numKey,100,i+1));
            }
        }
    }

    public MidiEvent makeEvent(int comd,int chan,int one,int two,int tick){
        MidiEvent event=null;
        try{
            ShortMessage a=new ShortMessage();
            a.setMessage(comd,chan,one,two);
            event=new MidiEvent(a,tick);
        }catch(Exception e){
            e.printStackTrace();
        }
        return event;
    }
}

服务端:

import java.io.*;
import java.net.*;
import java.util.*;



class MusicServer{
    ArrayList<ObjectOutputStream> clientOutputStreams;
    public static void main(String[] args){
        new MusicServer().go();
    }

    public class ClientHandler implements Runnable{
        ObjectInputStream in;
        Socket clientSocket;
        
        public ClientHandler(Socket socket){
            try{
                clientSocket=socket;
                in= new ObjectInputStream(clientSocket.getInputStream());
            }catch(Exception ex){
                ex.printStackTrace();
            }
        }

        public void run(){
            Object o2=null;
            Object o1=null;
            try{

                while((o1=in.readObject())!=null){
                    o2=in.readObject();

                    System.out.println("read two objects");
                    tellEveryone(o1,o2);
                }
            }catch(Exception ex){ex.printStackTrace();}
        }
    }
    public void go(){
        clientOutputStreams=new ArrayList<ObjectOutputStream>();

        try{
            ServerSocket serversock=new ServerSocket(4242);

            while(true){
                Socket clientSocket=serversock.accept();
                ObjectOutputStream out=new ObjectOutputStream(clientSocket.getOutputStream());
                clientOutputStreams.add(out);

                Thread t=new Thread(new ClientHandler(clientSocket));
                t.start();

                System.out.println("got a connection");
            }
        }catch(Exception ex){
            ex.printStackTrace();
        }
    }

    public void tellEveryone(Object one,Object two){
        Iterator it=clientOutputStreams.iterator();
        while(it.hasNext()){
            try{
                ObjectOutputStream out=(ObjectOutputStream) it.next();
                out.writeObject(one);
                out.writeObject(two);
            }catch(Exception ex){ex.printStackTrace();}
        }
    }


}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Daydreamer_777

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值