通信小项目——小小聊天室

       在这一块纠结了好久,不知道是不是因为前面漏掉了及时总结的环节,才导致现在的混乱和零散。像是在努力建造一栋大楼,前面一直在捡拾建材,终于着手要开始建造的时候,却发现每一块材料都需要反复雕琢加工,框架和样式都在脑子里,每一步要做什么甚至也一目了然,因为每一步都似曾相识,但每一步又着实走得很艰难。。。虽然举步维艰,但只要坚持,我们就始终都在进步,每一天,哪怕只是填一粒沙,也会有意想不到的收获。接下来我就来讲讲自己一步步蹭过来的通信之路。。。
       首先,亮出核心思想——“大局观”!
       这是本次挑战过程中我体会最深的一点。依然用建造楼房来说,假如没有设计师的设计图纸,仅凭建筑师天马星空地堆砖头,那么也许做到一半会突然发现哪一部分受到影响无法继续下去,然后就要拆掉产生影响的部分,拆到一半又发现后面还会再用到这里,于是半路停手,继续建造其他部分,做到一半又突然发现少了什么东西,然后这边砌块砖、那边堆块瓦,堆着堆着就不知道自己究竟干了些什么,只得放弃,最终变成烂尾。。。但如果事先经过精心研究和设计,按照整理好的思路一步步进行,那么过程就会变得格外清晰顺畅。可见,整体框架和思路至关重要!
       接下来就要着手做我的小小聊天室啦!
       分析:若想实现群聊功能,就要有能够处理客户机信息的服务器,然后通过方法调用,将某一客户机发来的消息转发给其他的每一位在线用户。那么首先,我们就要想办法实现一台客户机和服务器之间的通信。这样可以把任务粗略地分成三块:1.服务器;2.客户机;3.建立链接。具体步骤如下:
    一.构造服务器和客户机界面,添加主要组件,如:服务器连接按钮、客户机登陆按钮、消息输入框、客户机消息显示框、发送按钮等等。如:服务器界面构造——

package lyd_p130730群聊服务器;

import java.awt.FlowLayout;
import java.awt.Label;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class ChatServer {
	
	public void initGUI(){
		JFrame jf = new JFrame();
		jf.setSize(700,500);
		jf.setTitle("服务器");
		jf.setResizable(false);
		jf.setDefaultCloseOperation(3);
		jf.setLayout(new FlowLayout());
		//端口连接
		Label l = new Label("服务器端口:");
		jf.add(l);
		JTextField jtf_conn =new JTextField(7);
		jf.add(jtf_conn);
		JButton jb_conn = new JButton("连接");
		jf.add(jb_conn);
		//显示消息
		JTextArea jta_msg = new JTextArea(20,50);
		jta_msg.setEditable(false);
		jf.add(jta_msg);
		//发送消息
		JTextField jtf_msg =new JTextField(40);
		jf.add(jtf_msg);
		JButton jb_msg = new JButton("发送");
		jf.add(jb_msg);
		//界面可见
		jf.setVisible(true);
		//加监听器
		ServerLis sl1 = new ServerLis(jtf_conn,jta_msg);
		jb_conn.addActionListener(sl1);
		ServerLis sl2 = new ServerLis(jtf_conn,jta_msg);
		jb_conn.addActionListener(sl2);
	}
	public static void main(String[] args) {
		ChatServer cs = new ChatServer();
		cs.initGUI();	
	}
}

   二.关键代码
        //在服务器界面输入端口号后,点击创建,等待客户机连入
        ServerSocket server = new ServerSocket(9000);

        client = server.accept();
        //客户端创建和连接
        Socket client = new Socket(localhost,9000);
        //从客户机获取输入输出流
        DataOutputStream dos = new DataOutputStream(client.getOutputStream());

        DataInputStream dis = new DataOInputStream(client.getInputStream());
        dis = new DataInputStream(client.getInputStream());

        dos = new DataOutputStream(client.getOutputStream());

 

   三.由于实现群聊需要多个客户机同时连入,因此需要启动一个线程,将客户机连接放进线程当中,并在其中定义一个服务器处理客户机的方法。

package lyd_p130730群聊服务器;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import javax.swing.JTextArea;

public class ServerThread extends Thread{
	
	private ServerSocket ss;
	private JTextArea jta_msg;
	public ServerThread(ServerSocket ss,JTextArea jta_msg){
		this.ss = ss;
		this.jta_msg=jta_msg;
	}
	private Thread iothread;
	private OutputStream ous;
	private InputStream ins;
	
	public void run(){
		process();
	}
	
	//定义一个处理客户机的方法
	public void process(){
		while(true){
		try {
		//等待客户机连入
		final Socket client = ss.accept();
		System.out.println("等待结束啦!!!");
		//创建处理客户机的线程
		Thread iothread = new Thread(){
			public void run(){
				handleClients();
				readMsg();
			}
			//定义一个处理客户机的具体方法
			public void handleClients(){
				try {
				ous = client.getOutputStream();
				ins = client.getInputStream();
				//读写数据
				String s ="Welcome~\r\n";
				//获取字节
				byte[] data = s.getBytes();
				//用输出对象发送数据
				ous.write(data);
				//强制输出
				ous.flush();
				//关闭连接
				client.close();
			} catch (Exception e) {
				e.printStackTrace();}
		}
		//定义一个服务器读取消息的方法
		public void readMsg(){
			BufferedReader brd = new BufferedReader(new InputStreamReader(ins));
			try {
			String msg = brd.readLine();
			jta_msg.append(msg);
			} catch (Exception e) {
			e.printStackTrace();}
			}
			};
			} catch (Exception e) {
			e.printStackTrace();}
			}	
	}		
	//定义一个服务器给一个客户机发送消息的方法
	public void sendMsg(String msg){
		try {			
			ous.write(msg.getBytes());
			ous.flush();
		} catch (IOException e) {
		e.printStackTrace();
		}
	}
}

     四.读取和发送消息。

//定义一个服务器给一个客户机发送消息的方法
	public void sendMsg(String msg){
		try {			
			ous.write(msg.getBytes());
			ous.flush();
		} catch (IOException e) {
		e.printStackTrace();
		}
	}

五.实现群聊时,还需要创建一个队列,用以保存每一个创建服务器并连入客户机的线程。 

package lyd_p130730群聊服务器;

import java.io.IOException;

public class ThreadArray {
	
	private static String msg;
	
	//定义用于存储线程的队列
	public static java.util.ArrayList<ServerThread> array = new java.util.ArrayList<>();
	//定义添加线程的方法
	public void addThread(ServerThread st){
		array.add(st);
		System.out.println(st+"上线啦!!!");
	}
	//定义删除线程的方法
	public void removeThread(ServerThread st){
		array.remove(st);
		System.out.println(st+"要下线啦,886 !!!");
	}
	}

 六.群聊,即服务器读取某一客户机发来的信息,再转发给所有在线用户。因此需要在上面队列类中定义一个群发的方法,即 遍历数组,对每一个Client对象调用sendMsg()方法。

 

//定义一个将消息发送给所有用户的方法
	public static void sendAll(String str){
		//遍历数组
		for(int i = 0;i<array.size();i++){
			ServerThread st = array.get(i);
			st.sendMsg(msg);
		}
	}

      至此,聊天室的基本框架就大体完成啦,由于类比较多,涉及到许多传参的问题,因此出现了很多空指针的报错,另外,由于一开始思路不清晰导致代码混乱,使得该项目两次无法继续进行而重新开始,慢慢理清思路的过程中也对通信有了更深入地理解,至于传输图片等功能还有待探索和实践,希望自己能够把握基本框架,带着清晰的思路在通信之路上越走越顺~O(∩_∩)O~

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值