Java IO之Socket通信

一、通讯协议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();
        }
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值