前段时间悲剧的生病了,所以通信阶段的学习也就停了下来,这段时间身体见好,所以在家看了看书。虽然生病前已经写好过一个多线程服务器,但是来不及总结,整体结构也相当混乱,所以在此重新写了一遍,也算是复习一下。
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的详细讨论(作者不是本人),有兴趣的可以下载看看。
分享到:
相关推荐
初识鲁迅——少年闰土PPT.ppt
初识单片机—— 十字路口交通灯的.ppt
初识JavaScript ———(2)!!!.md
初识JavaScript———(1)!!!.md
01第1章 初识C++——C++程序设计入门,视频类资源。不过这里只有一本书的第一章
PLC技术及应用
PLC技术
PLC技术及应用
PLC技术
PLC技术及应用
IOC-InversionofControl,译为控制反转,是一种遵循依赖倒置原则的代码设计思想。所谓依赖倒置,就是把原本的高层建筑依赖底层建筑“倒置”过来,变成底层建筑依赖高层建筑。高层建筑决定需要什么,底层去实现这样的...
初识PLC——PLC性能共28页.pdf.zip
初识PLC——PLC发展共41页.pdf.zip
初识PLC——PLC工作原理共9页.pdf.zip
初识PLC——认识FXN系列PLC共8页.pdf.zip
交流JTAG跟我学JTAG协议破解——第一弹初识JTAGTAP状态机.pdf
初识PLC——PLC编程软件的使用共21页.pdf.zip