`
Coco_young
  • 浏览: 125766 次
  • 性别: Icon_minigender_1
  • 来自: 湖南长沙
社区版块
存档分类
最新评论

初识通信——多线程服务器的建立

阅读更多
前段时间悲剧的生病了,所以通信阶段的学习也就停了下来,这段时间身体见好,所以在家看了看书。虽然生病前已经写好过一个多线程服务器,但是来不及总结,整体结构也相当混乱,所以在此重新写了一遍,也算是复习一下。


package Practice1_ThreadServer;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

/**
 * 服务器端的线程类,负责处理客户端
 * @author yfr
 *
 */
public class ServerThread extends Thread {

	private Socket client;//客户端
	private OutputStream ous;//输出流
	private InputStream ins;//输入流
	
	/**
	 * 构造函数
	 * @param client :传入客户端对象
	 */
	public ServerThread(Socket client){
		this.client = client;
		try {
			ous = this.client.getOutputStream();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * 传送消息给客户端
	 * @param msg: 消息
	 */
	private void sendMsg2Client(String msg){
		
		byte[] data = msg.getBytes();
		try {
			ous.write(data);
			ous.flush();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * 读取字符串的方法
	 * @return 读取的字符串
	 * @throws Exception 
	 */
	private String readString() throws Exception{
		
		//获得输入流
	    ins = client.getInputStream();
		//创建字符串缓冲区
		StringBuffer stb = new StringBuffer();
		
		int data = 0;
		int EXIT = 13;//当读到回车就表示已经读到了一个字符串
		
		while(data!=EXIT){
			
			data = ins.read();
			
			stb.append((char)data);
			
		}
		
		return stb.toString().trim();
	}
	
	/**
	 * 处理客户端的方法
	 */
	private void ProcessClient(){
		
		//发送欢迎消息给客户端
		String WelComeMsg = "你好,欢迎来到老杨的服务器\r\n";
		sendMsg2Client(WelComeMsg);
		
		String ClientMsg = "";
		String EXIT = "bye";
		
		//当读到的消息不是bye时 表明聊天还没结束
		while(!ClientMsg.equals(EXIT)){
			try {
				ClientMsg = readString();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			String tempMsg = "服务器收到:"+ClientMsg+"\r\n";
			sendMsg2Client(tempMsg);
		}
		
		//发送再见消息
		String BYBYEMsg = "期待下次光临\r\n";
		sendMsg2Client(BYBYEMsg);
		
		//关闭与服务器的连接
		try {
			client.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	/**
	 * 线程运行
	 */
	public void run(){
		ProcessClient();
	}
	
	
	
}


package Practice1_ThreadServer;
import java.net.ServerSocket;

/***
 * 服务器主类
 * @author yfr
 *
 */
public class ServerMain {

	/**
	 * 主函数
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		
		ServerMain sm = new ServerMain();
		sm.setUpServer(9090);

	}
	
	/**
	 * 创建服务器
	 * @param port :端口号
	 * @throws Exception 
	 */
	private void setUpServer(int port) throws Exception{
		//创建服务器对象
		java.net.ServerSocket server = new ServerSocket(port);
		
		boolean  Working = true;//服务器的工作状态
		
		while(Working){
			
			//循环等待接收客户端对象
			java.net.Socket client = server.accept();
			
			//创建一个线程对象
			ServerThread dealMachine = new ServerThread(client);
			
			//启用线程单独去处理
			dealMachine.start();
			
		}
		
	}

}





编写完这个多线程服务器后,小结如下几点:
1.正确使用ServerSocket类建立服务器,并接收Socket对象。
2.使用telnet网络命令,连接上服务器。
3.理解Socket对象的输入输出流,并能使用它们在服务器和客户端之间实现简单信息的传输。
4.利用Thread实现多个客户端同时连接上服务器



初识通信,印象深刻只有10个字“服务器”,“客户端”,“数据传输”。



另外一点,是关于StringBuffer 和 String 的一点讨论:


/**
	 * 读取字符串的方法
	 * @return 读取的字符串
	 * @throws Exception 
	 */
	private String readString() throws Exception{
		
		//获得输入流
	    ins = client.getInputStream();
		//创建字符串缓冲区
		StringBuffer stb = new StringBuffer();
		
		int data = 0;
		int EXIT = 13;//当读到回车就表示已经读到了一个字符串
		
		while(data!=EXIT){
			
			data = ins.read();
			
			stb.append((char)data);
			
		}
		
		return stb.toString().trim();
	}


如果把这段代码改成:
/**
	 * 读取字符串的方法
	 * @return 读取的字符串
	 * @throws Exception 
	 */
	private String readString() throws Exception{
		
		//获得输入流
	    ins = client.getInputStream();
		//创建字符串缓冲区
		String stb = "";
		
		int data = 0;
		int EXIT = 13;//当读到回车就表示已经读到了一个字符串
		
		while(data!=EXIT){
			
			data = ins.read();
			
			stb+=(char)data;
			
		}
		
		return stb.trim();
	}
	

是否具有同样的效果呢?开始我也想了很久,后来查资料发现,表面上是一样的效果,但是效率确是不一样的,引用人家的解释如下:
首先,
public class xx {public static void main(String[] args) { String s1 = "You are hired!";String s2 = "You are hired!";if (s1==s2) {System.out.println("一个内存空间");} else {System.out.println("不是一个内存空间");}}}
打印的结果是:一个内存空间
这里==的意义是两个操作数是否指向同一个对象
可见s2在不用new创建的情况下会自动检索到具有相同内容的内存空间中共享,那么既然s1和s2共享了同一个对象
再看下面的代码


public class xx {public static void main(String[] args) { String s1 = "You are hired!";String s2 = "You are hired!";s1 = s1.replace('h','f');System.out.println(s1);if (s1==s2) {System.out.println("一个内存空间");} else {System.out.println("不是一个内存空间");}}}
代码结果是
You are fired!
不是一个内存空间
可见,String中s1的内容虽然被改写,但是已经不在是原来第一次分配到的那个内存空间,也就是String类的内容能被改变,但一旦改变系统将为其分配新的内存
说到与stringBuffer的区别,从根本上来说应该是
stringBuffer在做字符长度变动的时候将继续使用原来的内存空间,不新分配.
而String的长度一旦变动,就如上面的例子一样,其内部将分配新的内存空间.  

在java中有3个类来负责字符的操作。
1.Character 是进行单个字符操作的,
2.String 对一串字符进行操作。不可变类。
3.StringBuffer 也是对一串字符进行操作,但是可变类。
String:
是对象不是原始类型.
为不可变对象,一旦被创建,就不能修改它的值.
对于已经存在的String对象的修改都是重新创建一个新的对象,然后把新的值保存进去.
String 是final类,即不能被继承.
StringBuffer:
是一个可变对象,当对他进行修改的时候不会像String那样重新建立对象
它只能通过构造函数来建立,
StringBuffer sb = new StringBuffer();
note:不能通过付值符号对他进行付值.
sb = "welcome to here!";//error
对象被建立以后,在内存中就会分配内存空间,并初始保存一个null.向StringBuffer
中付值的时候可以通过它的append方法.
sb.append("hello");
字符串连接操作中StringBuffer的效率要比String高:
String str = new String("welcome to ");
str += "here";
的处理步骤实际上是通过建立一个StringBuffer,让侯调用append(),最后
再将StringBuffer toSting();
这样的话String的连接操作就比StringBuffer多出了一些附加操作,当然效率上要打折扣.
并且由于String 对象是不可变对象,每次操作Sting 都会重新建立新的对象来保存新的值.
这样原来的对象就没用了,就要被垃圾回收.这也是要影响性能的.


由此可见,当需要频繁的对字符串进行修改连接操作时,选用StringBuffer的效率会比String高很多。至此终于理解为什么用StringBuffer。最后再上传一份关于StringBuffer StringBuilder String的详细讨论(作者不是本人),有兴趣的可以下载看看。
2
2
分享到:
评论

相关推荐

    初识JavaScript ———(2)!!!.md

    初识JavaScript ———(2)!!!.md

    初识JavaScript———(1)!!!.md

    初识JavaScript———(1)!!!.md

    01第1章 初识C++——C++程序设计入门

    本章"初识C++——C++程序设计入门"是学习C++之旅的起点,旨在为初学者构建坚实的基础。 首先,C++程序的基本结构通常包括预处理指令、函数定义、变量声明和控制流语句。预处理指令以`#`开头,如`#include`用于引入...

    初识PLC——PLC性能.pptx

    FX0N系列拥有20条基本指令和2条步进指令,而FX1N系列则增加了更多的指令,包括27条基本指令和2条步进指令,以及丰富的应用指令,如计数、定时、比较、移位等,以满足更复杂的控制需求。 综上所述,FX系列PLC具备了...

    初识PLC——PLC发展.ppt

    3. I/O单元:连接CPU与外部设备,负责信号的转换和传递,确保PLC与生产设备间的数据通信。 总的来说,PLC以其高效、灵活、可靠的特性,成为现代工业自动化的核心组件,极大地推动了工业生产效率的提升。

    初识PLC——PLC工作原理.ppt

    4. **系统监控阶段**:在此阶段,PLC会进行自我诊断和通信任务,检查硬件状态,处理网络通信,并准备进行下一个扫描周期。 ### 扫描周期 PLC的工作是周期性的,每个完整的扫描过程称为一个扫描周期。扫描周期包括...

    初识鲁迅——少年闰土PPT.ppt

    【初识鲁迅与《少年闰土》】 鲁迅,原名周树人,是中国现代文学史上的巨匠,同时也是一位深思熟虑的思想家、革命家和教育家。他的笔名“鲁迅”在1918年首次出现在我国现代文学史上具有里程碑意义的白话小说《狂人...

    初识PLC——认识FXN系列PLC.ppt

    PLC技术

    初识PLC——PLC编程软件的使用.ppt

    PLC技术及应用

    初识单片机—— 十字路口交通灯的.ppt

    这篇文档主要介绍的是初学者如何理解并应用单片机来实现十字路口交通灯的控制。在交通灯控制中,单片机是核心控制器,它负责根据预设的时间序列来切换不同方向的信号灯状态,以确保交通流畅和安全。...

    初识Spring——Spring核心容器

    IOC-InversionofControl,译为控制反转,是一种遵循依赖倒置原则的代码设计思想。所谓依赖倒置,就是把原本的高层建筑依赖底层建筑“倒置”过来,变成底层建筑依赖高层建筑。高层建筑决定需要什么,底层去实现这样的...

    初识Python——基本图形绘制

    在Python编程中,初学者经常会接触到turtle库,这是一个非常实用且有趣的模块,它允许我们创建基本的图形和图像。在本文中,我们将深入探讨turtle库的一些核心概念和功能。 首先,turtle库概述:turtle库是Python...

    通信工程-通信工程图纸初识.pptx

    通信工程是信息技术领域的重要组成部分,涉及网络建设、信号传输、数据通信等多个方面。在实际的工程实践中,通信工程图纸的勘察设计与制图是至关重要的环节。本篇内容主要介绍了通信工程图纸的初步认识和使用CAD...

    读书笔记 |《大话移动通信》

    读书笔记 |《大话移动通信》书籍信息书名:《大话移动通信》作者:丁奇 阳桢出版社:人民邮电出版社本书解决的问题初识移动通信构建移动通信学习基本脉络框架书籍内容结构第一章:点对点的无线通信——从贝尔到...

    精选_【Cocos Creator 联机实战教程(1)】——初识Socket.io_源码打包

    【Cocos Creator 联机实战教程(1)】——初识Socket.io 是一个针对游戏开发者,特别是使用Cocos Creator的开发者的系列教程。本教程旨在帮助他们掌握如何利用Socket.io实现在Cocos Creator游戏中的实时通信功能,这...

    大模型扫盲系列——初识大模型.docx

    大模型扫盲系列——初识大模型.docx

Global site tag (gtag.js) - Google Analytics