网络通信基础小结1——一个简单的可以读写消息的服务器
开学一个月了,主要在学习网络通信。感觉这一块需要相当好的逻辑能力和全局感,因为代码量很大,需要调用的函数也很多,需要遵守的读写顺序,规则,以及流程也有很多。所以总结是十分有必要的!为了理清思路好好的往后面学,从今天开始我会每天更新一点我之前做过的有关通信内容的总结。这一块我目前大致做到了6步:1,实现简单的可以读取字符串的服务器,用DOS系统下自带的客户端登陆。2,在这基础上实现多线程服务器,允许和多个客户同时通信。3,简单的客户端。4,实现有界面的通信客户端和服务器。5,XMPP风格协议的通信客户端和服务器。6,字节流协议传文件。那么闲话先不多说,让我直入主题。
首先,谈一下如何实现一个简单的可以读取字符串的服务器。让我们先来理清楚如何通信这个概念,实现通信无非就是要在服务器和客户端之间搭建一个可以交流的管道,
1.我们首先创建一个服务器ServerSocket对象
// 在指定的端口上构造服务器对象 java.net.ServerSocket ss = new java.net.ServerSocket(port); System.out.println("服务器构建成功,等待端口" + port);
2.再通过调用它的accept()方法等待一个客户端Socket对象连接进入,这里我用了while (true)的方法,目的是为了让服务器进入循环等待,即如果一个客户端断开连接,只要服务器不关闭它还可以再次连接。当然这里的while(true)用的是有缺陷的,这还需要在以后的代码中继续改进!
while (true) {//让服务器进入循环等待,即如果一个客户端断开连接,只要服务器不关闭它还可以再次连接 java.net.Socket client = ss.accept();
3.当一个客户端连接进入以后我们就从这个Socket对象上得到输入输出流来搭建这个管道。
//从连接对象上得到输入流对象,用于读取 java.io.InputStream ins = client.getInputStream(); java.io.OutputStream ous = client.getOutputStream();
管道一旦连通搭建好就可以收发消息啦~
由于还要收发字符串,所以我们这里分析一下读取字符串的方法。首先,通信的实质是传输一个个的字节,所以,这里我们构建一个字符串缓冲区,来读取每一个字节。
//创建一个字符串缓冲区 StringBuffer stb = new StringBuffer();
读取字符串的过程中,read()方法也要产生一个阻塞。也就是说我们要读取完整的一句话。这里我用回车换行符来实现这个阻塞,即只有读取到一个回车换行符的时候才算读取了完整的一句话!回车换行符是”\r\n”,r对应的字节是10,而n对应的字节是13,所以只要读取到一个字节值为13或10的字节,我们就把它组成一句话,并让服务器读取这句话:
char c=0; while(c!=13){ //遇到一个换行就是一句话 int i = ins.read();//读取客户机发来的一个字节 c=(char)i;//将输入的字节转化为一个char stb.append(c); }
最后再把上述的封装成一个方法,这样每次服务器调用这个方法就等于是读取了客户家发来的完整的一句话了!
下面我把上述描述的组合起来,给出实现最最基础的服务器的源代码:
public class ChatServer { public static void main(String args[]) { ChatServer cs = new ChatServer(); int port = 9090; cs.setUpServer(port); } // 在指定端口上启动服务器 public void setUpServer(int port) { try { // 在指定的端口上构造服务器对象 java.net.ServerSocket ss = new java.net.ServerSocket(port); System.out.println("服务器构建成功,等待端口" + port); // 调用服务器accept方法,当有客户机连上时,返回代表他们之间连接的socket对象 while (true) {//让服务器进入循环等待,即如果一个客户端断开连接,只要服务器不关闭它还可以再次连接 java.net.Socket client = ss.accept(); // 调用处理客户机与服务器通信的方法 processClient(client); } } catch (Exception ef) { ef.printStackTrace(); } } public void processClient(java.net.Socket client) { try { String clientAdder = client.getRemoteSocketAddress().toString(); System.out.println("连接进的客户地址是:" + clientAdder); // 从连接对象上得到输入流对象,用于读取 java.io.InputStream ins = client.getInputStream(); // 从连接对象上得到输出流对象,用于写入 java.io.OutputStream ous = client.getOutputStream(); // 刚连接上时给客户机发消息 String outStr = clientAdder + "欢迎你!\r\n";// 每条消息事宜\r\n结尾的行消息 ous.write(outStr.getBytes()); ous.flush(); String input = readString(ins); while (!"bye".equals(input)) {// 当客户机输入了一个bye,即断开连接 System.out.println("客户机发来的消息是:" + input); outStr = "服务器收到了你的消息" + input + "\r\n"; ous.write(outStr.getBytes()); ous.flush(); input = readString(ins);// 再次读取客户机发来的消息 } // 如果客户机发送了"bye"消息,即要求退出 outStr = "再见\r\n"; ous.write(outStr.getBytes()); ous.flush(); // 关闭连接 client.close(); } catch (Exception e) { e.printStackTrace(); } } private String readString(InputStream ins) throws Exception { // 创建一个字符串缓冲区 StringBuffer stb = new StringBuffer(); char c = 0; while (c != 13) { // 遇到一个换行就是一句话 int i = ins.read();// 读取客户机发来的一个字节 c = (char) i;// 将输入的字节转化为一个char stb.append(c); } String input = stb.toString().trim(); return input; } }
总结一下这个最简单的服务器,我觉得我们首先要了解一个通信的实质,那就是在客户端和服务器之间搭建一个可以沟通的桥梁这里通过服务器的accept方法连上一个客户端,在调用客户端的输入输出流搭建通信管道。这里有两处阻塞的地方,第一是服务器的aceept方法来等待连接的时候,还有一个是读取字符串的时候。难点大致就是这些。最后通过cmd打开命令行 输入telnet 你的IP地址 端口号 就可以实现聊天啦~当然这个服务器还有很多的缺陷需要改进,具体的请看以后的日志~