`
xiaxia0402
  • 浏览: 19585 次
  • 性别: Icon_minigender_2
  • 来自: 长沙
文章分类
社区版块
存档分类
最新评论

通信总结一

阅读更多

一、创建一个简单的服务器:

 

1、  在指定端口创建一个java.net.ServerSocket服务器对象。

     java.net.ServerSocket server = new java.net.ServerSocket(port);

2、  让服务器对象进入等待状态,等待客户机来连结。并且设定在while(true){}中循环等待,连结了一个客户端后,等待下一个客户机的连结。

     java.net..Socket client = server.accept();

3、  从上一步的连结对象上面得到输入输出流。

4、  通过输入流从客户端读取数据,从输出流向客户端中写入数据。

5、  在命令行通过telnet连结上启动的服务器,可以互相发送字符串。

 

 

二、多线程的服务器

客户机往往有多个,对于一个服务器来说,处理多个客户机的方法就是每接入一个客户机就启动一个连结对象来处理与客户机的通信,这就可以通过添加一个用来处理服务器端与客户机的连结对象的线程类完成。每连入一个客户机就启动一个处理线程。线程类中放入读取客户机消息并发送消息的方法。

public class ClientThread extends Thread{

	
	private java.net.Socket client;
	private java.io.OutputStream ous;
	
	public ClientThread(java.net.Socket client){
		//创建这个线程对象时,传入一个他要处理的连结对象
		this.client = client;
	}
	
	public void run(){
		processClient(this.client);
	}
	
	/**
	 * 发送消息给客户端
	 * @param mag:从客户端读到的字符串
	 */
	public void senMsg2Me(String msg){
		try{
		byte[] data = msg.getBytes();
		ous.write(data);//向输出对象中写入数据
		ous.flush();//强制输出
		}catch(Exception ef){
			ef.printStackTrace();
		}
	}
	
	/**
	 * 处理客户进入的连结对象
	 * @param client
	 */
	private void processClient(java.net.Socket client){
		try{
		//3.从socket连结对象上调用方法得到输入输出流
		ous = client.getOutputStream();
		InputStream ins = client.getInputStream();
		
		//4.从输入流中读取数据,向输出流中写入数据。
		String s = "欢迎来聊天!\r\n";
		this.senMsg2Me(s);
		
		//调用读取字符串的方法,从输入流中读取一个字符串
		String inputS = this.readString(ins);
		
		while(!inputS.equals("bye")){
		
			System.out.println("客户机说:"+inputS);
			s = "服务器收到的是:"+inputS+"\r\n";
			this.senMsg2Me(s);
			inputS = this.readString(ins);
		}
		s = "你好,欢迎再来。\r\n";
		this.senMsg2Me(s);
		client.close();
		
		}catch(Exception ef){
			ef.printStackTrace();
		}
	}
	/**
	 * 从输入流对象中读取字节,拼成一个字符串返回
	 * 
	 * @param ins:输入流对象
	 * @return
	 * @throws IOException 
	 */
	private String readString(InputStream ins) throws Exception{
	
		//创建一个字符串缓冲区
		StringBuffer stb = new StringBuffer();
		char c = 0;
		while(c!=13||c!=-1){
			
			int i = ins.read();
			System.out.println("读到的字节是:"+i);
			c = (char)i;
			stb.append(c);
			
		}
		//将独到的字节数组转换为字符串,并去掉尾部空格
		String inputS = stb.toString().trim();
		
		return inputS;
		
	}
}

 

 

 其中包含一个读取字符串的方法readString(InputStream ins),是否还有更简单的解决方法?

 

三、读写字符串的方法

最初解决字符串读取的方法,就是创建一个字符串缓冲区,循环着一个一个字节的从客户机的输入流读取,并将字节转换为char类型,通过append方法组合成为字节数组。读到回车符时(即13),将append的字节数组转换为字符串输出到客户端。不过这个方法在读取中文字符串时会有乱码,因为一个中文需要两个字节来表示,而这种方法只能一个一个的来读取,转换成字符串时就会出错不能还原成为中文。

不过其实有个BufferedReader类,可以从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组、行的高校读取。

首先用BufferedReader包装输入流,缓冲指定文件的输入。

//将输入流封ins装为可以读取一行字符串,也就是以\r\n皆为的字符串

              BufferedReader brd = new BufferedReader(new InputStreamReader(ins));

然后调用readLine()方法读取字节并将其转换为字符返回是更为高效的方法

//调用读取字符串的方法,从输入流中读取一个字符串

              String inputS = brd.readLine();

四、公聊服务器的实现

公聊服务器中,每登录一个新的客户机,会通知其他用户有一个新用户上线,下线同理;另外,某一个客户机发送的消息,服务器会转发给其他所有在线用户,实现群聊的功能。流程也更为复杂:

1、  每有一个新的客户端连结,服务器会要求输入用户名及密码。

2、  服务器验证用户信息是否正确。若信息不相符,则提示用户信息有错。

3、  若通过验证,则给其他客户机发送消息:该用户上线,目前在线人数几人。

4、  在线用户可向服务器发送消息,服务器会转发给其他所有的在线用户。

5、  当某个客户端退出,服务器通知其他客户机:某用户下线,当前在线人数几人。

 

 

这里公聊的服务器增加了验证登陆信息、转发消息等多个功能,也就需要增加几个类来辅助。首先对于登陆用户来说,需要验证其用户名和密码,曾设一个DaoTools类:负责验证用户名和密码是否正确。验证用户信息的过程可以首先模拟一个数据库,用一个map存储用户名和对应的用户信息,在运行到验证模块前就将设置好的数据存入MAP,验证时,通过用户名得到对应的用户类,也就得到了该用户密码,验证是否符合。因此,也就需要创建一个用户信息类,其中存储用户名,密码以及以后可能用到的IP地址、登录时间等等信息。转发消息作为另外一个独立功能,也需要建立一个辅助类,其中放置通知上下线以及转发消息的方法。因为上线用户个数不定,可用一个队列来存放客户端处理线程类每增加一个客户连入,则启动一个处理线程,加入到队列中,而当前在线人数就是该队列的长度。转发消息则只要遍历队列,发送消息即可达成。

综上,总共需要设置五个类:

ChatServer类:创建服务器并等待连结。

ServerThread类:处理连结的线程类,读取客户端输入流并发送给客户端。

UserInfo类:用户信息类,存放用户属性。

DaoTools类:一个辅助类,使用时并不需要创建对象,直接调用其中存放的方法就好,因此其中的方法都是static方法。这个类中存放的是验证用户登录的方法。

ChatTools类:同样不需要创建对象,是一个辅助方法,转发客户机发送的消息,并有将新上线的用户即一个线程加入队列或者下线用户移除队列的方法。

上述两个辅助类都只只要调用其中方法的,可能觉得创建这两个类不是那么必要,不过因为类的职责要单一,这样也使得编程思路更加的清晰。

下面是这两个辅助类的代码:

 

/**
 * 转发消息的辅助类,只需调用该类的方法,不用创建对象,所以皆为静态方法
 * @author Administrator
 *
 */
public class ChatTools {

	private static ArrayList<ClientThread> ctList = new ArrayList<ClientThread>();
	
	/**
	 * 添加连结线程到队列的方法
	 * @param client
	 */
	public static void addClient(ClientThread ct){
		ctList.add(ct);
		castMsg(ct.getOwnUser(),"我上线了,当前在线人数:"+ctList.size());
		
	}
	/**
	 * 
	 * @param ct
	 */
	public static void removeClient(ClientThread ct){
		ctList.remove(ct);
		castMsg(ct.getOwnUser(),"我下线了,当前在线人数:"+ctList.size());
	}
	
	/**
	 * 转发消息的方法
	 * @param msg
	 */
	public static void castMsg(UserInfo sender,String msg){
		msg = sender.getName()+":\r\n"+msg;
		for(int i=0;i<ctList.size();i++){
			ClientThread ct = ctList.get(i);
			ct.senMsg2Me(msg);//发消息给每一个客户机
		}
	}
	
}

 

 

 

以及验证信息的辅助类:

//用户信息验证
public class DaoTools {
	
	//用户信息数据库
	private static java.util.Map<String, UserInfo> userDB = new java.util.HashMap<String, UserInfo>();
	
	
	/**
	 * 登录验证的方法
	 * @param user
	 * @return
	 */
	public static boolean checkLogin(UserInfo user){
		String name = user.getName();
		String pwd = user.getPwd();
	
		if(userDB.containsKey(name)){//如果用户名存在
			//得到数据库中的用户和密码
			UserInfo userInDB = userDB.get(name);
			String pwdInDB = userInDB.getPwd();
			if(pwd.equals(pwdInDB)){//验证密码
				return true;
			}
		System.out.println("您输入的密码不正确!");
		}
		return false;
	}
	
	
	static{
		
		for(int i = 0;i<10;i++){
			UserInfo user = new UserInfo();
			user.setName("user"+i);
			user.setPwd("pwd"+i);
			userDB.put(user.getName(), user);
		}
		
	}
	
}

 这里用到静态块,将预设的用户名和密码保存到一个map中,在加载java类的时候,首先执行类里面的static代码块,然后进入main入口函数,因此在验证方法被调用前,map中就有了预设的用户信息,可以验证用户登录。

分享到:
评论

相关推荐

    移动通信总结.docx

    移动通信总结全文共9页,当前为第1页。移动通信总结全文共9页,当前为第1页。移动通信总结 移动通信总结全文共9页,当前为第1页。 移动通信总结全文共9页,当前为第1页。 一、移动通信概念 移动通信是指通信双方至少...

    移动通信期末总结.doc

    1. 名词解析 信令:在电信网的两个实体... 过境切换:移动台穿越工作于不同的小区时发生的切换 软切换:移动台在从一个小区进入另一个小区时,先建立与新基站的通信,直到接收到 原基站信号低于一个门限值时再切断与原

    语音通信系统学习总结

    双方开始通信之前,需要为通信双方分配一条具有固定带宽的通信网络,通信双方在通信过程中将一直占用所分配的资源,直到通信结束。并且在电路的建立和释放过程中都需要利用相关的信令协议。 优点:通信过程中可以...

    北理工《通信电路与系统》复习总结

    【请用OneNote打开】北京理工大学《通信电路与...每章的复习为PPT+手写批注的形式,对重点内容和不容易理解的地方进行了说明和阐释,在“通信电路知识点合集”分页中将前几章的重点整合到了一块儿。以上仅供复习参考。

    [020]VC++串口通信总结.zip上位机开发VC串口学习资料源码下载

    [020]VC++串口通信总结.zip上位机开发VC串口学习资料源码下载[020]VC++串口通信总结.zip上位机开发VC串口学习资料源码下载[020]VC++串口通信总结.zip上位机开发VC串口学习资料源码下载[020]VC++串口通信总结.zip...

    Socket通信总结_13邵温财1

    Socket通信总结_13邵温财1

    进程管理与通信总结

    进程与程序区别:进程是程序的一次动态执行过程.进程在内存中运行,程序在磁盘中存储. 线程:LWP 进程的通信 BSD(高校):pipe、fifo、信号 System V:share memory、消息队列、信号灯(ftok) BSD:Socket

    IIC通信总结

    I2C(Inter-Integrated Circuit BUS) 集成电路总线,该总线由NXP(原PHILIPS)公司设计,多用于主控制器和从器件间的主从通信,在小数据量场合使用,传输距离短,任意时刻只能有一个主机等特性。

    北邮杨鸿文老师公开课通信原理知识点总结

    之前看了杨鸿文老师的通信原理的视频,总结了一下知识点,和北邮书的全部章节比起来不全,大家可以用来过一遍。

    通信行业20年报与21一季报总结:通信行业维持较快增长,估值整体处于低位,运营商板块业绩企稳回升.pdf

    通信行业20年报与21一季报总结:通信行业维持较快增长,估值整体处于低位,运营商板块业绩企稳回升.pdf

    《光纤通信》刘增基 第二版 总结

    《光纤通信》刘增基 第二版 总结 西安理工大学 考试专用

    服务通信方案总结

    一共有两个项目,一个项目充当服务端,使用aidl进程通信控制另一个项目,播放音乐,其中还包括Activity和Service之间的通信方案,Parcel绑定和接口回调……

    通信原理的实验

    通信原理实验的教科书 第一章 实验系统概述 1.1 概述 ...实验一 时分复用(TDM)通信系统综合实验 实验二 HDB3线路编码通信系统综合测试 实验三 BPSK(DBPSK)调制+汉明码系统测试 附录(电路原理图)

    通信实习报告总结.pdf

    通信实习报告总结1 时光如梭,转瞬⾃⼰的⼤学⽣活的第⼀年即将结束。⼀年的时间,⾃⼰学到了很多,也得到了很多,作 为学习通信⼯程专业的学⽣,作为以后即将成为⼀名通信⼈的学⽣来说,了解通信基础知识,掌握通信...

    移动通信重点总结.doc

    一、填空 1】第一代、第二代、第三代通信系统的主要特性、双工方式、多址方式、语音信号的速 率等。 答案:第一代移动通信系统 --- 1G:模拟系统 基本特征:模拟技术、模拟电路, FDMA/FDD; 蜂窝结构、漫游、切换;...

    移动通信总结3.docx

    移动通信总结3 频谱分配方法:1. 为特定目的而分配的频谱段,以拍卖的形式进行分配;2.除拍卖以外,一些特定频段被作为开放频段而留出,只要符合一定的行业规定,就可以无需许可而免费使用; 3. 另一种频谱分配方式...

    linux实现软中断通信和管道通信报告(含代码)

    1) 编制实现软中断通信的程序 使用系统调用fork()创建两个子进程,再用系统调用signal()让父进程捕捉键盘上发出的中断信号(即按delete键),当父进程接收到这两个软中断的某一个后,父进程用系统调用kill()向两...

    通信行业2019年报&2020一季报总结:5G与云新基建提速,AIOT开启创新周期.pdf

    通信行业2019年报&2020一季报总结:5G与云新基建提速,AIOT开启创新周期.pdf

    1移动通信重点总结.doc

    第一章概论 1、移动通信的特点。 1、移动通信必须利用无线电波进行信息传输 2、移动通信是在复杂的干扰环境中运行的 3、移动通信可以利用的频谱资源非常有限 4、移动通信系统的网络结构多种多样,网络管理和控制必须...

    移动通信技能技术总结1G~4G发展史.pdf

    移动通信技能技术总结1G~4G发展史.pdf

Global site tag (gtag.js) - Google Analytics