Java socket 套接字实现私聊群聊

  大一在校,第一次写博客,最近写了用Java Socket实现的简单私聊群聊,代码本身存在问题,就是在这里记录一下成长历程,意识到自己现在很菜,以后会多找些小项目练手,多写博客。这个程序其中有不少不完善的地方,各位不要借鉴。。。。。。委屈

   欢迎指正

   关于思路问题就是制定一个自己的通讯协议,比如正常文字消息就直接群发,遍历outputstream,如果是@+对方昵称+:就把名字提取出来,利用HashMap映射发给该昵称对应的输出流。客户端窗口为windowbuilder构造。下面是代码:

server类:

import java.awt.Button;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;


import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;


public class Server extends JFrame implements ActionListener{

//创建服务器界面类
    private JButton btn,btn1;
    private JLabel label;
    private ServerSocket sereverSocket;
    public static ClientMap<String, DataOutputStream> clients=new ClientMap<>();
    
public static void main(String[] args) {
Server server =new Server();

}


public Server() {
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
initialize();
}


//创建服务器界面
private void initialize() {
btn=new JButton("开启服务器");
btn1=new JButton("关闭服务器");
btn1.setEnabled(false);
btn.addActionListener(this);
btn1.addActionListener(this);
label = new JLabel("服务器未开启");
        getContentPane().add(label);
        getContentPane().add(btn);
        getContentPane().add(btn1);
        setTitle("服务器端");
        getContentPane().setLayout(new GridLayout(3, 0, 0, 0));
        setSize(500, 350);
        setLocation(200, 200);
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
}
    
//对按钮创建监听器
@Override
public void actionPerformed(ActionEvent e) {
// TODO 自动生成的方法存根
if(e.getSource()==btn) {
label.setText("服务器已开启!");
btn.setEnabled(false);
btn1.setEnabled(true);


try {
sereverSocket=new ServerSocket(Constant.port);

while(true) {

Socket socket=sereverSocket.accept();
Thread thread =new Thread(new ServerThread(socket));
thread.start();
label.setText("服务器已开启");

}
} catch (IOException e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
}

}else if(e.getSource()==btn1) {
label.setText("服务器已关闭!");
btn.setEnabled(true);
btn1.setEnabled(false);
    System.exit(0);
}
  }

      }

ServerThread类:

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;


public class ServerThread implements Runnable{

//服务器端线程类
private Socket socket;
private DataInputStream inputStream=null;
private  DataOutputStream outputStream=null;


public ServerThread(Socket s) {
this.socket=s;
}


@Override
public void run() {
// TODO 自动生成的方法存根
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {

inputStream =new DataInputStream(socket.getInputStream());
outputStream =new DataOutputStream(socket.getOutputStream());

String content=null;
while((content=inputStream.readUTF())!=null) {
if(content.startsWith(Constant.USER)) {
String name=getName(content);
if(Server.clients.containsKey(name)) {

System.out.print("该用户名已存在!!!请重新设置昵称!");
}else{
Server.clients.put(name, outputStream);

for(DataOutputStream outputStream:Server.clients.ValueSet()) {
outputStream.writeUTF(df.format(new Date())+"\n"+name+"进入了聊天室!");
}
}
}else if(content.startsWith(Constant.U)) {
String name_1=getChatName(content);
String primsg=getRealMsg(content);
Server.clients.get(name_1).writeUTF(df.format(new Date())+"\n"+"私聊<----+++&&&+++---->"+Server.clients.getKeyByvalue(outputStream)+"对你说:"+primsg);
}else {
String whoSend=Server.clients.getKeyByvalue(outputStream);
for(DataOutputStream outputStream:Server.clients.ValueSet()) {
outputStream.writeUTF(df.format(new Date())+"\n"+whoSend+":"+content);
}
}
}
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}

//提取登录名
private String getName(String s) {
return s.substring(2);
}

//提取私聊对象昵称
private String getChatName(String s) {
return s.substring(1, s.indexOf(Constant.colon));
}

//提取私聊信息内容
private String getRealMsg(String s) {
return s.substring(s.indexOf(":"));
}


}

ClientMap类:

import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;


//通过API了解到HashMap类,继承HashMap类,通过用户昵称到其对应输出流的映射,实现私聊,群聊
public class ClientMap<K, V> extends HashMap<K, V> {


  //根据Value删除指定项
      public void removeByValue(Object value) {
      for(Object key:keySet()) {
      if(get(key)==value||get(key).equals(value)) {
      remove(key);
      break;
      }
      }
      }
      
      //获取Value列表
      public Set<V> ValueSet(){
      Set<V> valueList=new HashSet<V>();
      for(Object key:keySet()) {
      valueList.add(get(key));
      }
      return valueList;
      }
      
      //重写put方法
      public V put(K key,V value) {
      for (V val:ValueSet()) {
      if(val==value||val.equals(value)) {
      throw new RuntimeException("value重复!");
      }
      }
      return super.put(key, value);
      }
      
      public K getKeyByvalue(Object value) {
      for(K key:keySet()) {
      if(get(key)==value||get(key).equals(value)) {
      return key;
      }
      }return null;
      }

}

Constant常量类:

public class Constant {
//常量类
    public static final String USER="用户";
    public static final String U="@";
    public static final String colon=":";
    public static final int port=8899;

}

Client类:

import java.awt.EventQueue;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Date;


import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.naming.spi.DirStateFactory.Result;
import javax.swing.JButton;
import javax.swing.JTextArea;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.SwingConstants;
import java.awt.Toolkit;


public class Client implements Runnable{
    
//创建用户界面类
private JFrame frame;
private JTextField textField;
private JTextField textField_1;
private JTextArea textArea;
private JButton button_1 ;
private JScrollPane scrollPane;
private Socket socket=null;
private DataInputStream inputstream=null;
private DataOutputStream outputstream=null;


/**
* Launch the application.
*/
public static void main(String[] args) {

    Client client = new Client();
client.frame.setVisible(true);
Thread thread = new Thread(client);
        thread.start();


}


/**
* Create the application.
*/
public Client() {
initialize();


try {
socket=new Socket("127.0.0.1",Constant.port);
inputstream=new DataInputStream(socket.getInputStream());
outputstream=new DataOutputStream(socket.getOutputStream());
} catch (UnknownHostException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}

}
    
  
/**
* Initialize the contents of the frame.
* 创建用户端界面
*/
private void initialize() {
frame = new JFrame();
frame.setIconImage(Toolkit.getDefaultToolkit().getImage(Client.class.getResource("/images/qq.png")));
frame.setTitle("\u5317\u533A3012\u5C0F\u7EC4-\u591A\u7A97\u53E3\u7248");
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
try {
                    if (socket != null)
                        socket.close();
                    if (inputstream!= null)
                        inputstream.close();
                    if (outputstream != null)
                        outputstream.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
}
});
frame.setBounds(100, 100, 744, 409);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);

JLabel label = new JLabel("\u6635\u79F0 \uFF1A");
label.setBounds(49, 33, 58, 15);
frame.getContentPane().add(label);

textField = new JTextField();
textField.setBounds(100, 31, 265, 21);
frame.getContentPane().add(textField);
textField.setColumns(10);

JButton button = new JButton("\u767B\u5F55");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String s1=textField.getText();

if(textField.getText().length()==0) {
textArea.append("昵称不能为空!\n");
}else {

textField.setEditable(false);
button.setEnabled(false);

String s2=Constant.USER+s1;
try {
outputstream.writeUTF(s2);

} catch (IOException e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
}

                   if(Server.clients.containsKey(s1)) {
                   textArea.append("用户名重复!");
                   }else {
                  
   button_1.setEnabled(true);
                   }


}


}
});
button.setBounds(389, 30, 97, 23);
frame.getContentPane().add(button);

JScrollPane scrollPane_1 = new JScrollPane();
scrollPane_1.setBounds(38, 69, 473, 223);
frame.getContentPane().add(scrollPane_1);

textArea = new JTextArea();
scrollPane_1.setViewportView(textArea);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
textArea.setEditable(false);

textField_1 = new JTextField();
textField_1.setBounds(31, 322, 372, 21);
frame.getContentPane().add(textField_1);
textField_1.setColumns(10);

button_1 = new JButton("\u53D1\u9001");
button_1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String s=textField_1.getText();
if(!s.equals("")) {
try {
outputstream.writeUTF(s);
} catch (IOException e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
}
} textField_1.setText("");
       }
});
button_1.setBounds(418, 324, 97, 23);
frame.getContentPane().add(button_1);
button_1.setEnabled(false);

JTextArea textArea_1 = new JTextArea();
textArea_1.setEditable(false);
textArea_1.setText("\u4F7F\u7528\u8BF4\u660E\uFF1A1.\u767B\u9646\u540E\u76F4\u63A5\r\n\r\n\u53D1\u6D88\u606F\u4E3A\u7FA4\u804A\uFF1B2.@+\u5BF9\r\n\r\n\u65B9\u6635\u79F0+\uFF1A(\u4E2D\u6587\u5192\u53F7)+\r\n\r\n\u5185\u5BB9\u5373\u53EF\u8FDB\u884C\u79C1\u804A\u3002");
textArea_1.setBounds(541, 43, 143, 318);
frame.getContentPane().add(textArea_1);



}


@Override
public void run() {
// TODO 自动生成的方法存根
try {
            inputstream = new DataInputStream(socket.getInputStream());


            while (true) {
                String s = inputstream.readUTF();
                textArea.append(s+"\n");
            }
        } catch (IOException e) {
        }

}
}



猜你喜欢

转载自blog.csdn.net/weixin_41004620/article/details/80867460