您的位置:首页 > 编程语言 > Java开发

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();
}
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  socket