网络通信基础第二式——创建循环等待的多线程服务器

[size=large] 想必你已经浏览过我的前一篇博文《网络通信基础第一式——创建简单服务器》,并发现了这个简单的服务器的诸多bug。例如:其中有一个极大的缺陷,当一个客户机连接上来后,收到服务器发出的一条消息,按照程序的执行顺序,服务器程序就退出了,如此不稳定的服务器如何让用户信任?当这个问题解决之后,你又会发现新的问题,当用两个telnet客户端连接服务器时,只有一个可以通信,前一个退出后,后一个才能通信,这个也是很致命的问题。一个服务器怎么只能让一个客户机接入呢?实在是太浪费了。。。
下面,我们就一一解决上诉问题。
首先,我们先解决服务器不稳定的问题。通过将ServerSocket的accep()在一个循环中调用,实现服务器的循环等待。即当一个客户机通信完毕后,服务器就在此进入循环中,重新调用accep()方法等待下一个客户机的接入,代码示例如下:[/size]
			while (true) {
// 当有客户机连接进来时,返回一个连接对象
java.net.Socket client = server.accept();// 阻塞,等待客户机连结进入
System.out.println("有一个客户机访问!");
// 从连结对象上取得输入输出流
java.io.InputStream ins = client.getInputStream();
ous = client.getOutputStream();
String msg = "Hello!\r\n";
ous.write(msg.getBytes());
String input = readString(ins);
while (!input.equals("bye")) {
this.jtre.append(input + "\r\n");
System.out.println("服务器收到的消息是:" + input);
input = readString(ins);
}
msg = "再见!\r\n";
ous.write(msg.getBytes());
// 关闭连结
client.close();
System.out.println("一个客户机断开了!");
}

[color=blue]注:如果你要控制服务器的启动和停止,硬编码while的条件为true可不是个好主意,后面会慢慢完善![/color]
[size=large] 随后,我们将要解决下一个问题,即让多个客户机接入服务器。我们将进入服务器的每一个连接对象(Socket)交由一个线程对象去处理,随后而来的其他连接就不用再等待了。将服务器改造为多线程服务器模型,示意图如下:[/size][img]http://dl.iteye.com/upload/attachment/395076/1e27e6d2-4434-3303-afa2-34d89694c019.jpg[/img]
[size=large]代码示例如下:[/size]
/**
* 服务器端处理与客户机连接对象的线程类封装
* @author king
*
*/
public class ServerThread extends Thread {

private java.net.Socket client;// 线程对象要处理的连接变量
// 创建输入输出流对象
private InputStream ins;
private OutputStream ous;

public ServerThread(java.net.Socket client) {
this.client = client;
}

public void run() {
processChat(client);
}

/**
* 处理客户端套接字对象:读取客户机发来的消息,并回显给客户机
*
* @param client
* :与客户机连接的套接字对象
* @throws Exception
*/
public void processChat(java.net.Socket client) {

try {
//从连接对象上得到输入/输出流对象
ins = client.getInputStream();
ous = client.getOutputStream();
// 服务器发送消息给客户机
String msg = "您好!我是服务器king。。。\r\n";
sendMsg(msg);
// 调用读取字符串的方法,从输入流中读取一个字符
String input = readString(ins);
while (!input.equals("bye")) {
System.out.println("客户机说:" + input);
msg = "服务器收到的是:" + input + "\r\n";
System.out.println(msg);
sendMsg(msg);
input = readString(ins);// 读取客户机的下一次输入
}
msg = "再见,欢迎下次再来!\r\n";
ous.write(msg.getBytes());
// 关闭连结
client.close();
System.out.println("一个客户机断开了!");
} catch (Exception e) {
e.printStackTrace();
}
}

public void sendMsg(String msg) throws Exception {
byte[] data = msg.getBytes();
ous.write(data);// 用输出对象发送
ous.flush();// 强制输出
}

/**
* 服务器从输入流中读取字节,并拼成字符串返回 如果读到字节是13,服务器认为以前的一段字节为一个字符串
*
* @param ins
* :服务器的输入流的对象
* @throws Exception
* @return:服务器从输入流(客户机发来的)读到的字符串
*/
public String readString(java.io.InputStream ins) throws Exception {

// 创建一个字符串的缓冲区
StringBuffer stb = new StringBuffer();
// 客户机向服务器发送消息
int i = 0;
while (i != 13) {// 读到一个回车,就是一句话
i = ins.read();// 读取客户机发来的下一个字节
stb.append((char) i);// 把字节转化为字符,并加到缓冲区内
}
String s = stb.toString().trim();// 将字节组(缓存区内的)转化为字符串
s = s.trim();// 调用trim去掉尾部的空格
return s;

}
}

[size=large] 现在的服务器已经可以同时处理多个客户机的连接请求啦,可以说已经完成了一个服务器的雏形,后面就是不断地完善过程啦!敬请期待。。。[/size]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值