Java IO之Socket通信
2016-07-05 15:25
501 查看
一、通讯协议TCP、UDP
Java Socket通信是基于TCP协议来完成的。讲Socket通信之前有必要先了解这两种底层协议。TCP协议是面向连接、保证高可靠性(数据无丢失、数据无失序、数据无错误、数据无重复到达)传输层协议。TCP协议通过三次握手建立连接,四次握手断开连接,带重传功能的肯定确认来保证可靠传输。其中HTTP协议就是基于TCP协议来实现的。HTTP1.0默认短连接,HTTP1.1默认使用长连接,通过Keep-Alive来控制长连接时间,在同一个TCP连接中,只有上一个请求得到响应之后下一个请求才会发送。
UDP协议是无连接,不保证可靠的传输层协议。传输数据之前源端和终端不建立连接,当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。其实“ping”命令的原理就是向对方主机发送UDP数据包,然后对方主机确认收到数据包,如果数据包是否到达的消息及时反馈回来,那么网络就是通的。
二、字符流和字节流
java在对文件、图片、视频等资源的操作上提供了字符流和字节流的操作方式,但是由于计算机中使用的是二进制来存储文件,而字符流对文件操作时会经历编码和解码阶段,所以字节流的操作要比字符流的操作效率高。但是字符流有很多操作都方便编程人员,对于文件的读取展现,我们可以使用字符流,免去了我们程序对字节和字符的转换。除此之外,字符流与字节流还有一个根本的区别。字节流不需要用到缓冲区,而字符流会先将数据放到缓存区再写入文件。如下例子,我们为了研究字符流和字节流是否用到缓冲区,不关闭输出流,因为在关闭输出流之前,会将缓冲区的内容全部输出,类似于调用flush()。字节流:
package ioTest; import java.io.FileOutputStream; public class ByteTest { public static void main(String[] arg) { try { FileOutputStream fileOutputStream = new FileOutputStream("e:/ds2.txt"); fileOutputStream.write("hello world".getBytes()); //fileOutputStream.close(); } catch (Exception e) { e.printStackTrace(); } } }
结果:文件ds2.txt显示【hello world】。
字符流:
package ioTest; import java.io.FileWriter; import java.io.IOException; public class CharTest { public static void main(String[] arg){ try { FileWriter fileWriter = new FileWriter("e:/ds.txt"); fileWriter.write("hello world"); //fileWriter.close(); } catch (IOException e) { e.printStackTrace(); } } }
结果:文件ds.txt文件内容为空。
二进制I/O中常用的流操作类
InputStream:FileInputStream、FilterInputStream、ObjectInputStream。
FilterInputStream:DateInputStream、BufferedInputStream。
FileInputStream以文件、文件名为构造函数创建输入流,是大部分输入流的起始点,其他输入流通过包装该输入流来进行操作。
DateInputStream通过包装FileInputStream或其他字节输入流来构造,提供了多种数据读取方式,readByte()、readChar()、readInt()、readLine()、readUTF()等等。
BufferedInputStream在读取文件时创建缓冲区,默认是512字节。
ObjectInputStream包含所有DateInputStream的功能,另外还增加了对对象的操作。
文本I/O中常见的流操作
BufferedReader、InputStreamReader、FileReader
FileReader大部分字符流读取文件的起点。
InputStreamReader连通字符流与字节流的枢纽,可以通过字节流来构造该字符流,然后通过其他字符流再包装该字符流,并且设置编码方式。如:
new BufferedReader(new InputStreamReader(new FileInputStream(fileName),"UTF-8"));
BufferedReader在读取文件时创建缓冲区。
三、通信实现
前面介绍了相关的基础知识之后就直接上代码吧,另外对于多线程不太熟悉的朋友自己去补习一下。本程序包含三个类,具体的运行步骤在代码中做了详细的解释:SocketClient:socket通信客户端,运行时可以多次启动来模拟多个客户端。
SocketServer:socket通信服务端,这里只有一个服务端,对于不同的客户端请求创建不同的线程来进行处理,通过线程池来进行管理。
SocketThread:socket通信基础线程,供服务端调用,用于与客户端进行交互。
package socketTest; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; import java.util.Scanner; public class SocketClient { private DataOutputStream out;//通信输出流 private DataInputStream in;//通信输入流 private Socket socket; public static void main(String[] arg){ try { SocketClient socketClient = new SocketClient(); socketClient.initParam("127.0.0.1",6644); System.out.println("请输入向服务器发送的内容:"); socketClient.send(); } catch (Exception e) { e.printStackTrace(); } } //初始化参数 public void initParam(String ipAddress, int port) throws Exception{ this.socket = new Socket(ipAddress, port); this.out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream())); this.in = new DataInputStream(new BufferedInputStream(socket.getInputStream())); } //发送内容 public void send() throws IOException{ while(true){ Scanner scanner = new Scanner(System.in); String input = scanner.nextLine(); out.writeUTF(input); out.flush(); if("exit".equals(input)){ //获取服务器端断开连接的信息 String serverInput = in.readUTF(); System.out.println(serverInput); //客户端断开连接 System.out.println("客户端关闭连接"); in.close(); out.close(); socket.close(); break; } } } }
package socketTest; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SocketServer{ private ServerSocket serverSocket; private ExecutorService threadPool; private static final int THREADCOUNT = 5; public static void main(String[] arg){ SocketServer socketServer = new SocketServer(); try { socketServer.initParam(6644); socketServer.getRequest(); } catch (Exception e) { socketServer.threadPool.shutdown(); e.printStackTrace(); } } //初始化参数 public void initParam(int port) throws Exception{ this.serverSocket = new ServerSocket(port); this.threadPool = Executors.newFixedThreadPool(THREADCOUNT); } //获取客户端请求 public void getRequest() throws IOException{ while (true) { Socket socket = this.serverSocket.accept(); SocketThread socketThread = new SocketThread(socket); threadPool.execute(socketThread); } } }
package socketTest; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; public class SocketThread implements Runnable { private Socket socket; private DataInputStream in;//通信输入流 private DataOutputStream out;//通信输出流 public SocketThread(Socket socket){ try { this.socket = socket; this.in = new DataInputStream(new BufferedInputStream(socket.getInputStream())); this.out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream())); } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { try { String clientInput; while((clientInput = in.readUTF())!=null){ System.out.println(clientInput); if("exit".equals(clientInput)){ out.writeUTF("服务器已关闭连接"); out.close(); in.close(); socket.close(); System.out.println("服务端关闭连接"); break; } } } catch (IOException e) { e.printStackTrace(); } } }
相关文章推荐
- java-模拟tomcat服务器
- Linux socket 初步
- java socket 注意的地方
- java socket 注意的地方
- C#基于socket模拟http请求的方法
- 简单的Ruby中的Socket编程教程
- Socket不能选择本地IP连接问题如何解决
- C#之Socket操作类实例解析
- 使用C#来编写一个异步的Socket服务器
- C#使用Socket快速判断数据库连接是否正常的方法
- 科学知识:理解socket
- websocket++简单使用及实例分析
- Android聊天工具基于socket实现
- php与flash as3 socket通信传送文件实现代码
- 解决time_wait强制关闭socket
- asp.net使用Socket.Send发送信息及Socket.SendFile传输文件的方法
- C#使用Socket上传并保存图片的方法
- 深入php socket的讲解与实例分析
- Linux网络编程之UDP Socket程序示例
- Linux网络编程之socket文件传输示例