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

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

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();

}

}

}



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

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

[size=small]
另外一点,是关于StringBuffer 和 String 的一点讨论:[/size]

/**
* 读取字符串的方法
* @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 都会重新建立新的对象来保存新的值.
这样原来的对象就没用了,就要被垃圾回收.这也是要影响性能的.


[size=medium]由此可见,当需要频繁的对字符串进行修改连接操作时,选用StringBuffer的效率会比String高很多。至此终于理解为什么用StringBuffer。最后再上传一份关于StringBuffer StringBuilder String的详细讨论(作者不是本人),有兴趣的可以下载看看。[/size]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值