Socket编程
2015-08-06 21:36
363 查看
最近想写一个IM软件,因此研究了一下Socket编程,发现写Socket的时候有许多容易被忽略的细节需要注意,特做笔记记录。
需要注意:
1.client端的connect方法和server端的accept方法是线程阻塞的,也就是说,在返回结果以前,线程是阻塞的。
2.有些资料说服务端和客户端不能同时创建输入流,实际上这个说法并不准确,经验证,同时创建输入流是完全可以的。事实上,server和client不能同时从输入流读取数据。为什么呢,因为inputstream的read方法是线程阻塞的,如果两边同时读取的话,两端都在等待对方输出数据,造成IO阻塞,因此需要一方先输出数据,另一方读取。
3.socket.shutdownOutput()方法,该方法的作用是关闭输出流。经验证,上述代码中如果少了这句,client端会继续读取inputstream中的内容,也就是阻塞。也就是说,只有关闭流后,才能终止read方法的阻塞状态。
4.socket.setSoTimeout()方法,设置socket读取输入流时的等待超时时间,必须在阻塞方法(read)之前调用。
三.Socket的非阻塞式实现:
一.Socket定义
二.Socket的阻塞式实现:
客户端主要代码:
<span style="font-family:Microsoft YaHei;font-size:18px;">private Handler myHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case RECEIVE: tv_msg.append("Server Msg:" + msg.getData().getString("msg") + "\n"); break; } } };</span>
<span style="font-family:Microsoft YaHei;font-size:18px;">btn_msg.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { thread = new Thread(new MessageRunnable()); thread.start(); } });</span>
<span style="font-family:Microsoft YaHei;font-size:18px;">private class MessageRunnable implements Runnable { @Override public void run() { socket = new Socket(); Message message = new Message(); message.what = RECEIVE; Bundle bundle = new Bundle(); try { //连接服务器端的SOCKET socket.connect(new InetSocketAddress(serverIP, serverPort), 5000); //读出服务器端SOCKET的内容 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); OutputStream os = socket.getOutputStream();</span>
<span style="font-family:Microsoft YaHei;font-size:18px;"> //设置客户端的SOCKET读取inputstream的过时时间,如果服务端在这个时间内没有发送数据过来,则抛出SocketTimeoutException socket.setSoTimeout(2000); String line=null; String msg = ""; Log.v("MainActivity","ready to read form server"); System.out.println("ready to read form server"); while ((line = bufferedReader.readLine()) != null) { msg += line; } Log.v("MainActivity","read complete"); System.out.println("read complete"); //更新UI bundle.putString("msg", msg); message.setData(bundle); myHandler.sendMessage(message); //向服务器写内容 os.write(et_msg.getText().toString().getBytes("UTF-8")); os.flush(); //关闭各种流和SOCKET bufferedReader.close(); os.close(); } catch (SocketTimeoutException te) { te.printStackTrace(); //连接请求超时 bundle.putString("msg", "time out"); message.setData(bundle); myHandler.sendMessage(message); } catch (IOException e) { e.printStackTrace();</span> } } }
服务器端代码:
<span style="font-family:Microsoft YaHei;">public static void main(String args[]){ ServerSocket serverSocket=null; try{ serverSocket=new ServerSocket(port); }catch (IOException e){ e.printStackTrace(); } System.out.println("server socket created"); while(true){ try{ Socket socket=serverSocket.accept(); System.out.println("socket accepted"); new Thread(new Runnable(){ @Override public void run(){ BufferedReader reader=null; OutputStream out=null; try{ reader=new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8")); out=socket.getOutputStream(); System.out.println("server is ready to read"); String line=""; String next=null; while((next=reader.readLine())!=null){ line+=next; } System.out.println("read complete"); System.out.println("client msg: "+line); //Thread.sleep(5000); System.out.println("ready to write to client"); out.write("i am socket server".getBytes("UTF-8")); out.flush(); System.out.println("write complete"); // //socket.shutdownOutput(); }catch(IOException e){ e.printStackTrace(); } //catch (InterruptedException e) { // e.printStackTrace(); //} finally{ try{ out.close(); }catch (IOException e){ e.printStackTrace(); } try{ reader.close(); }catch (IOException e){ e.printStackTrace(); } } } }).start(); }catch(IOException e){ e.printStackTrace(); } } }</span>
需要注意:
1.client端的connect方法和server端的accept方法是线程阻塞的,也就是说,在返回结果以前,线程是阻塞的。
2.有些资料说服务端和客户端不能同时创建输入流,实际上这个说法并不准确,经验证,同时创建输入流是完全可以的。事实上,server和client不能同时从输入流读取数据。为什么呢,因为inputstream的read方法是线程阻塞的,如果两边同时读取的话,两端都在等待对方输出数据,造成IO阻塞,因此需要一方先输出数据,另一方读取。
3.socket.shutdownOutput()方法,该方法的作用是关闭输出流。经验证,上述代码中如果少了这句,client端会继续读取inputstream中的内容,也就是阻塞。也就是说,只有关闭流后,才能终止read方法的阻塞状态。
4.socket.setSoTimeout()方法,设置socket读取输入流时的等待超时时间,必须在阻塞方法(read)之前调用。
三.Socket的非阻塞式实现:
相关文章推荐
- Java实现算法之--求子数组和的最大值
- Ubuntu14.04安装PyCharm
- 用dom4j解析xml 报java.lang.NoClassDefFoundError:org/jaxen/JaxenException
- UE4 控制台管理器: 在C++中设置控制台变量
- 《unix环境高级编程》 有关I/O库函数--3
- 再谈TQ2440使用TFTP下载程序
- 【Java】Java处理double相加的结果异常
- JDK动态代理机制
- Spring注解详解
- myeclipse 提示No Default Proposals 或 no completions available 的解决方法
- 黑马程序员-----------C语言基础-----------运算符
- C++ Primer 知识点总结
- 解决Opentaps/OFBiz在Eclipse启动时"Could not load VFS configuration"的问题
- Blackjack 项目 in python
- 通过DexClassLoader动态加载代码
- 重温《C++ Primer》笔记十 当数组作为函数参数时
- 解决ofbiz在myeclipse中调试运行时报错:Can't find bundle for base name cache
- python练习之通过python pexpect实现自动生成openssl证书
- java设计模式(9) - 适配器模式
- java中进行二进制,八进制,十六进制,十进制间进行相互转换