Java Socket Server-Client模式 1.0
仅支持一问一答模式 , 由client先行发送消息 , 最后结束时由Client发出 “bye”。
收完才能发 , 发完才能收 收发无法同时进行
Server , Client类里用到了 读类型的 InputStreamReader , socket.getInputStream , BufferedReader() , System.in
以及 写类型的PrintWriter , socket.getOutputStream()。
1 /* 2 这是socket编程的第一个版本 , 仅能实现先由client端发一句话 , 3 然后在依次你一句我一句这样对话 , 结束方式是由client端发送bye。 4 5 现在想到的改进方式是用多线程 , 每个端都设置一个接收 一个发送 6 线程 , 互不干扰。 7 8 9 */ 10 package test; 11 12 import java.io.BufferedReader; 13 import java.io.IOException; 14 import java.io.InputStreamReader; 15 import java.io.PrintWriter; 16 import java.net.Socket; 17 import java.net.UnknownHostException; 18 19 public class Client { 20 21 22 public void initial() throws IOException { 23 24 try { 25 Socket socket = null; 26 socket = new Socket("127.0.0.1",4700); 27 BufferedReader bi = new BufferedReader(new InputStreamReader(System.in)); 28 BufferedReader biServer = null; 29 PrintWriter pw = null; 30 pw = new PrintWriter(socket.getOutputStream()); 31 biServer = new BufferedReader(new InputStreamReader(socket.getInputStream())); 32 String reply = null; 33 String message = bi.readLine();// 首先发声 , message获取键盘输入 34 while(!message.equals("bye") ) { 35 // System.out.println(message); 36 pw.println(message);//向Server发送message 37 pw.flush(); 38 39 reply = biServer.readLine();//阻塞 , 等待Server消息 40 System.out.println("Server: "+reply); 41 42 message = bi.readLine();// 现在获取buffer中的信息 , 以回车为结束 43 } 44 45 bi.close(); 46 biServer.close(); 47 pw.close(); 48 socket.close(); 49 } catch (UnknownHostException e) { 50 51 e.printStackTrace(); 52 } catch (IOException e) { 53 54 e.printStackTrace(); 55 } 56 57 } 58 59 60 61 public static void main(String[] args) { 62 Client client = new Client(); 63 try { 64 client.initial(); 65 } catch (IOException e) { 66 67 e.printStackTrace(); 68 } 69 70 } 71 }
1 /* 2 这是socket编程的第一个版本 , 仅能实现先由client端发一句话 , 3 然后在依次你一句我一句这样对话 , 结束方式是由client端发送bye。 4 5 现在想到的改进方式是用多线程 , 每个端都设置一个接收 一个发送 6 线程 , 互不干扰。 7 8 9 */ 10 package test; 11 import java.io.BufferedReader; 12 import java.io.IOException; 13 import java.io.InputStreamReader; 14 import java.io.PrintWriter; 15 import java.net.*; 16 public class Server { 17 ServerSocket serverSocket = null; 18 public void initial() { 19 try { 20 this.serverSocket = new ServerSocket(4700); 21 }catch(Exception e) { 22 System.out.println("创建端口失败"); 23 } 24 25 } 26 27 public void connect() { 28 Socket linkSocket = null; 29 try { 30 linkSocket = this.serverSocket.accept(); 31 }catch(Exception e) { 32 System.out.println("erro! :"+e); 33 } 34 35 try { 36 InputStreamReader isr = new InputStreamReader(linkSocket.getInputStream()); 37 BufferedReader br = new BufferedReader(isr); 38 PrintWriter pw = new PrintWriter(linkSocket.getOutputStream()); 39 BufferedReader bi = new BufferedReader(new InputStreamReader(System.in)); 40 String message = br.readLine();//阻塞 , 等待client传消息 41 String reply = null; 42 while(!message.equals("bye")) { 43 System.out.println("client: "+message); 44 reply = bi.readLine();//接收到了Client的信息 , 现在获取buffer中的信息 , 以回车为结束 45 pw.println(reply); 46 pw.flush(); //发送键盘输入的reply给client 47 message = br.readLine();//继续等待client的信息 48 49 } 50 pw.close(); 51 br.close(); 52 53 } catch (IOException e) { 54 // TODO Auto-generated catch block 55 e.printStackTrace(); 56 } 57 58 try { 59 linkSocket.close(); 60 } catch (IOException e) { 61 // TODO Auto-generated catch block 62 e.printStackTrace(); 63 } 64 } 65 66 public void close() { 67 try { 68 this.serverSocket.close(); 69 } catch (IOException e) { 70 // TODO Auto-generated catch block 71 e.printStackTrace(); 72 } 73 } 74 75 public static void main(String[] args) { 76 Server server = new Server(); 77 server.initial(); 78 server.connect(); 79 server.close(); 80 } 81 }
以上代码写的非常乱 , 很粗糙 , try catch写的非常没有逻辑 , 不想整理了,此为我的1.0版本。
接下来写一写我的一些收获:
1.java中IO流的操作
主要内容看收藏夹 , 本次主要使用了字符流 , BufferedReader br = new BufferedReader( new InputStreamReader( socket.getInputStream() ) );
用buffer 可以一次取一行用readLine() , 避免了用InputStreamReader的 read() , 循环取的麻烦。
针对于此次试验 ,
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String message = br.readLine();
这里会一直阻塞直到有输入 , 对于readLine()来说就是一点回车就从缓冲区拿走一句。
搜输入阻塞时的一个百度回答:
阻塞。。。
当前线程执行到需要输入时:
启动另一个线程接收数据(可能不是线程,总之是另一个事件),接收完后,再由这个线程唤醒当前线程。
至于更细点的就不好说了,毕竟键盘的输入都是驱动级的了,已经不能说是多线程了。
线程阻塞就是:暂停线程,由其它线程唤醒,自身无法唤醒
(自身唤醒的话应该叫休眠吧sleep,不过自身休眠了谁来接收数据)
2.
127.0.0.1回环ip(loopback) / 本机ip
netstat -a 查看端口使用情况
以后想到了再写 , 现在十周 周一 , 预计成品怎么也得是个多线程的 , 再搭一个图形界面。
11/6 15:23:58
更新22:59:20
晚上在hg机子上运行Server实际操作了一下发现了一些问题 , 总结一下就是对这个 buffer 以及reaLine方法还不太理解。
比如说你输完信息 , 按了回车 , 现在输入东西并按回车 不会显示在终端上 , 不过确实会发送到对方 , 即在对方的socket的 getOutputStream的 buffer里
比如你发完 hi了以后有输入了 , a+回车 *3
server接收到hi以后 回复 1 ,立即会收到 a ;再回复 1 , 立即回收到a , 直到把那三个a全接收完 。
昨天晚上说的好像不太对 , 情况应该是这样子的。
当某一方发完以后 , 因为等待对方而处于阻塞中 , 此时你再输入 “aa+回车” 则会进入system.in的buffer 里 (cmd里不会回显 , eclipse控制台会回显)
然后你需要等待收到对方消息后才能执行PrintWriter.println() , 而又因为此时你的 system inbuffer里已经有了“aa+回车” , 所以不需要再等待你输入(因为是readLine方法)就
可以立即执行PrintWriter.println(“aa”)。
其实问题说到底就是你发完后必须等着接收到了再发 , 即不能再等待接收的时候发送 , 等待接受的时候的输入会送到system.in的buffer里。
2017-11-07 21:19:49

浙公网安备 33010602011771号