java仿QQ通信项目实现二

java仿QQ通信-(客户端)

上一节我们实现了通信服务器端,这一节我们一起来完成客户端的代码。

将客户端封装为一个类:

首先每个客户端有一个Socket连接对象。假如我们要和服务器建立一条通信管道,这个对象将是客户端接收信息的端口。

这里的组赛机制是客户端不断从服务器读取信息,因此我们应该将读取信息放到独立的线程中。

根据通信协议,客户端要实现与服务器的通信,需要有以下方法:
1.连接服务器
2.在服务器注册账号
3.登陆服务器
4.与服务器聊天
5.向服务器发送消息:普通文本消息、文件消息等
6.意外退出程序的消息

package javaQQclient1;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

import MSGType.LoginMsg;
import MSGType.LoginResMsg;
import MSGType.MSGTools;
import MSGType.MSHead;
import MSGType.RegMsg;
import MSGType.RegResMsg;
import MSGType.TextMsg;

public class ChatClient extends Thread {
	
	private String serverIp;//连接的服务器的ip和端口
	private int serverPort;
	private int JKnum;//自己的账号和昵称还有密码
	private String nickname;
	private String pwd;
	private Socket client;//与服务器连接的对象
	private InputStream ins;//聊天的输入输出流
	private OutputStream ous;
	private DataInputStream din;//包装后的输入输出流
	private DataOutputStream dou;
	
	//通过给定的ip和端口建立客户对象
	public ChatClient(String ip, int port){
		this.serverIp=ip;
		this.serverPort=port;
	}
	
	
	//重写Run函数
	public void run(){
		try {
			ReadFromServer();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	//注册账号
	public void Register(String nickname, String pwd) throws IOException{
		int len= 13+10+10;
		byte type=0x01;
		RegMsg mg= new RegMsg(len,type,0,0,nickname,pwd);
		byte []data= MSGTools.packMsg(mg);
		dou.write(data);
		dou.flush();
	}

	//连接服务器
	public boolean conn2server(){
		try {
			client= new Socket(this.serverIp,this.serverPort);
			ins=client.getInputStream();
			ous=client.getOutputStream();
			din=new DataInputStream(ins);
			dou= new DataOutputStream(ous);
			return true;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}

	//登录服务器
	public void LoginServer(int JKnum, String pwd) throws IOException{
		int len=13+4+10;
		byte type=0x02;
		LoginMsg lg = new LoginMsg(len,type,0,0,JKnum,pwd);//登录请求消息
		byte []data=MSGTools.packMsg(lg);//消息打包
		dou.write(data);//发送消息
		dou.flush();
	}
	
	//读取服务器消息
	public void ReadFromServer() throws IOException{
		//不停从服务器读取消息
		while(true){
			MSHead msg=MSGTools.readMsgHead(din);//读取消息头
			byte type=msg.getType();
			if(type==0x11){//注册应答消息
				RegResMsg rrm=(RegResMsg)msg;
				byte state=rrm.getState();
				if(state==0){//注册成功
					JKnum=rrm.getDest();
					System.out.println("注册成功,您的JK号:"+JKnum);
				}
				else{//注册失败
					System.out.println("注册失败");
				}
			}
			else if(type==0x12){//登录应答消息
				LoginResMsg lrm=(LoginResMsg)msg;
				byte state=lrm.getState();
				if(state==0){//登录成功
					System.out.println("登陆成功!");
				}
				else{
					System.out.println("登陆失败!");
				}
			}
			else if(type==0x06){//普通文本消息
				TextMsg tm=(TextMsg)msg;
				int from=tm.getSender();
				String msgContent=tm.getmsgContent();
				System.out.println("收到来自"+from+"的消息:"+msgContent);
			}
			else if(type==0x07){//文件消息
				System.out.println("收到文件消息!");
			}
		}
	}

	//发送文本信息给dest账号
	public void sendMSG(String msg,int dest) throws IOException{
		byte[]data=msg.getBytes();
		int len=13+data.length;
		byte type=0x06;
		int src=JKnum;
		TextMsg tm= new TextMsg(len,type,dest,src,msg);//文本消息
		byte[]text=MSGTools.packMsg(tm);//消息打包
		dou.write(text);
		dou.flush();
	}
	
	//发送文件信息
	public void sendFile(String FileName,int dest){
		//待完善
	}
	
	//发送意外或者手动退出消息
	public void closeMe(){
		//待完善
	}
}

由于注册和登录应答消息都是在run函数里面通过调用readFromServer实现,因此我们在建立客户端的时候调用顺序必须为:
start()开启线程->
conn2Server()连接服务器->
Regsiter()注册或LoginServer()登录->
sendMSG()发送文本消息或sendFile()发送文件消息等等;
这样才能得到每个操作之后服务器的反馈信息;

下面我们写一个类来使用ChatClient类的方法,控制通信的流程

package javaQQclient1;

import java.io.IOException;

public class MainNetUI {
	private ChatClient chatter;
	//构造函数
	public MainNetUI(String ip,int port) throws IOException{
		chatter= new ChatClient(ip, port);
		chatter.conn2server();
		chatter.start();
		chatter.Register("哈哈哈", "123");
		chatter.sendMSG("你好,我是willow", 2022);
	}
	public static void main(String[]args) throws IOException{
		MainNetUI Chatter= new MainNetUI("localhost",11111);
	}
}


下面来完善客户端的其他功能:

发送文件消息:

		//发送文件信息
	public void sendFile(String FileName,int dest) throws IOException{
		File file = new File(FileName);//文件对象
		String name=file.getName();//文件名
		FileInputStream fin= new FileInputStream(file);//文件输入流
		int len=fin.available();
		byte[]FileData= new byte[len];//文件数据
		fin.read(FileData);
		fin.close();
		byte type=0x07;
		FileMsg fm= new FileMsg(13+256+len,type,dest,JKnum,name,FileData);
		byte[] data= MSGTools.packMsg(fm);
		dou.write(data);
		dou.flush();
	}

接收文件消息

	//保存文件
	public void SaveFile(String FileName,byte[]FileData) throws IOException{
		File file= new File(FileName);
		FileOutputStream fou= new FileOutputStream(file.getPath());
		fou.write(FileData);//将文件数据输出到文件
		System.out.println("文件"+FileName+"保存完毕!");
	}
发布了27 篇原创文章 · 获赞 1 · 访问量 1297

猜你喜欢

转载自blog.csdn.net/qq_43496675/article/details/104211189