socket通信 _ 一个简单的群聊系统
群聊系统要用到通信socket协议,在java中要用到两个类java.net.ServerSocket和
Java.net.Socket.ServerSocket用于创建服务器,而Socket用于创建连接。
简单介绍Socket通信的用法:
首先,我们建立一个简单的 “服务器—客户端”一对一的连接来说明如何用socket通信。
1.建立一个服务器ServerSocket server=new ServerSocket(port);
Port是一个整形数据,表示端口号,端口的范围是0~65534,而0~1024端口是系统预留端口,为避免端口被占用我们可以选择一个较大的数:int port=9900;
2.建立一个链接来连接服务器和客户端。
服务器:Socket socket_server=server.accept();这是一个死等函数,若没有成功建立连接,则程序不会向下执行。
客户端:Socket socket_client=new Socket(IPaddr,port);IPaddr表示你的网络IP地址,本系统在本机上运行可以用127.0.0.1代替,否则可以在命令行下输入ipconfig进行查找。Port为服务器建立的端口号。
3.完成这些以后我们就可以进行服务器和客户端之间的通信了。
发消息需要用到java.io.DataInputStream和java.io.DataOutputStream。
在发送端:DataOutputStream dout=new DataOutputStream(socket_sever.getoutputString);
dout.writeUTF(massage);
接收端:DateInputStream din=new DateInputStream(socket_client.getInputStream);
String accept=din.readUTF();
这样,服务器端和客户端就可以进行简单的通信了。当然,若想时时刻刻都能接收到信息,则必须把接受代码放入线程中让其循环执行。
群聊系统的设计:
服务器:
功能描述:创建一个服务器,接收来自客户端的消息,并分发给每个客户端。
1.建立服务器
public void BuildServer() { try { int port=9900; server = new ServerSocket(port); System.out.println("创建群聊服务器成功!"); InetAddress addr=InetAddress.getLocalHost(); System.out.println("本机地址:"+addr); //将网络地址和端口打印方便客户端进行连接 System.out.println("端口号:"+port); } catch (IOException e) { e.printStackTrace(); } }
2.创建socket,由于客户端不止一个,故socket也不只一个,我们可以将Socket=server.accept();循环执行。
@Override //这是重写Thread类中的run(); public void run() { while (true) { try { Socket socket = server.accept();
//链接建立后,接收客户端传来的用户名信息 DataInputStream in = new DataInputStream( socket.getInputStream()); String name=in.readUTF(); if (name.equals("")) name="匿名用户"; System.out.println(name + "已成功连接!"); try { DataOutputStream out = new DataOutputStream(socket.getOutputStream()); out.writeUTF(("亲爱的"+name+",你已连接到服务器!\n\r")); } catch (IOException e) { e.printStackTrace(); }
//这是一个线程类,之后将会创建,用于与客户端收发消息 GroupThread gt = new GroupThread(socket, list, name);
//list是一个链表,存储每个已存在的连接,其初始化:ArrayList<GroupThread> list = new ArrayList<GroupThread>(); list.add(gt); gt.start(); } catch (IOException e) { } }
3.主函数
public class GroupServer extends Thread { /** * @param 群聊服务器 */ ServerSocket server; ArrayList<GroupThread> list = new ArrayList<GroupThread>(); public void BuildServer() { } @Override public void run() { } public static void main(String[] args) { GroupServer s = new GroupServer(); s.BuildServer(); s.start(); } }
4.GroupThread类,用于服务器与客户端的收发信息,收到来自客户端的信息后分发出去。
public class GroupThread extends Thread{ Socket socket; String str; String accept; ArrayList<GroupThread> list; private String username; public GroupThread(Socket socket, ArrayList<GroupThread> list,String name){ this.socket=socket; this.list=list; this.username=name; } @SuppressWarnings("deprecation") public void run(){ while (true) { try { DataInputStream in = new DataInputStream( socket.getInputStream()); accept=in.readUTF(); if(!accept.equals("")){sendGroup(); } } catch (IOException e) { try {
//客户端关闭后断开连接,将这个链接从链表中移除,并停止线程 System.out.println(username+"已断开连接!"); list.remove(list.indexOf(this));this.stop(); socket.close(); } catch (IOException e1) { System.out.println("断开连接出现异常!"); } } } } private void sendGroup() { int index=list.indexOf(this); for(int i=0;i<list.size();i++){ if(index!=i){ list.get(i).Send(accept); } }
public void Send(String str){
try {
DataOutputStream out = new DataOutputStream(
socket.getOutputStream());
out.writeUTF(str);
} catch (IOException e) {
e.printStackTrace();
}
} }
客户端:
1.登陆界面,提取登录名(未做验证),用于显示群聊过程中的昵称
public class Login extends JFrame { private static final long serialVersionUID = 1L; private JTextField name = new JTextField(9); private JButton login = new JButton("登录"); public void showUI() { this.setTitle("请输入你的用户名"); this.setSize(300, 240); this.setDefaultCloseOperation(EXIT_ON_CLOSE); this.setLocationRelativeTo(null); this.setLayout(new FlowLayout()); this.setResizable(false); this.add(new JLabel("用户名:")); this.add(name); Listener listener=new Listener(this,name); name.addKeyListener(listener); this.add(login); login.setFocusable(false); login.addActionListener(listener); this.setVisible(true); } public static void main(String[] args) { new Login().showUI(); } } class Listener implements KeyListener,ActionListener{ Login login;JTextField jt; private String name; public Listener(Login login,JTextField jt){ this.jt=jt; this.login=login; } @Override public void actionPerformed(ActionEvent e) { name=jt.getText(); MyChat chat=new MyChat(name); try { chat.runit(); } catch (IOException e1) { e1.printStackTrace(); } login.setVisible(false); } @Override public void keyTyped(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) { } @Override public void keyReleased(KeyEvent e) { if(e.getKeyCode()==10){ name=jt.getText(); MyChat chat=new MyChat(name); try { chat.runit(); } catch (IOException e1) { e1.printStackTrace(); } login.setVisible(false); } } }
2.聊天界面
public class MyChat extends Thread { JButton send = new JButton("发送"); JTextField jt = new JTextField(20); JTextArea jta = new JTextArea(); DataOutputStream out; Socket socket; String str; byte secret=19; String name; ServerSocket server; JFrame thiss = new JFrame(); public MyChat(String name){ this.name=name; } public void client() throws IOException { thiss.setSize(400, 300); thiss.setLayout(new BorderLayout()); thiss.setDefaultCloseOperation(3); thiss.setLocationRelativeTo(null); JScrollPane js = new JScrollPane(jta); thiss.getContentPane().add(js); thiss.setResizable(false); JPanel south = new JPanel(); thiss.add(south, BorderLayout.SOUTH); south.add(jt); send.setFocusable(false); jta.setFocusable(false); jt.addKeyListener(new KeyListener() { @Override public void keyTyped(KeyEvent e) { } @Override public void keyReleased(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) { if (KeyEvent.getKeyText(e.getKeyCode()).equals("Enter")) { str = jt.getText() + "\n\r"; jt.setText(""); jta.append(name +":" + str); try { out = new DataOutputStream(socket.getOutputStream()); out.writeUTF(name +":" + str); } catch (IOException e1) { } } ; } }); send.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { str = jt.getText() + "\n\r"; jt.setText(""); jta.append(name+":" + str); try { out = new DataOutputStream(socket.getOutputStream()); out.writeUTF((name + ":" + str)); } catch (IOException e) { } } }); south.add(send); thiss.setVisible(true); } @SuppressWarnings("deprecation") public void run() { while (true) { try { DataInputStream in = new DataInputStream( socket.getInputStream()); String accept = in.readUTF(); if(!accept.equals(""))jta.append(accept); } catch (IOException e) { try { System.out.println("连接已断开!"); socket.close(); this.stop(); } catch (IOException e1) { e1.printStackTrace(); } } } } public void connect() { try { String addr="127.0.0.1";//本机地址 socket = new Socket(addr, 9900); out = new DataOutputStream(socket.getOutputStream()); out.writeUTF(name); thiss.setTitle(name); } catch (IOException e) { } } public void runit() throws IOException{ this.client(); this.connect(); this.start(); if(name.equals("")){name="匿名"; thiss.setTitle("匿名");} } }
运行结果: