Java Socket构建阻塞的TCP通信

4 篇文章 0 订阅

1.服务器端
1.创建ServerSocket对象,可在构造子中指定监听的端口;

privateintport = 8000;
private ServerSocket serverSocket;
……
serverSocket = new ServerSocket(port);

2.服务器端调用ServerSocket对象的accept()方法,该方法一直监听端口,等待客户的连接请求,如果接收到一个连接请求,accept()方法就会返回一个Socket对象,这个Socket对象与客户端的Socket对象将形成一条通信线路;

Socket socket = null;
socket = serverSocket.accept(); // 等待客户连接

3.Socket类提供了getInputStream()方法和getOutputStream()方法。

InputStream socketIn = socket.getInputStream();
OutputStream socketOut = socket.getOutputStream();

源代码EchoServer.java
publicclass EchoServer {
    privateintport = 8000;
    private ServerSocket serverSocket;
    public EchoServer() throws IOException {
       serverSocket = new ServerSocket(port);
       System.out.println("Server Start");
    }
    public String echo(String msg) {
       return"echo:" + msg;
    }
    private PrintWriter getWriter(Socket socket) throws IOException {
       OutputStream socketOut = socket.getOutputStream();
       returnnew PrintWriter(socketOut, true);
    }
    private BufferedReader getReader(Socket socket) throws IOException {
       InputStream socketIn = socket.getInputStream();
       returnnew BufferedReader(new InputStreamReader(socketIn));
    }
    publicvoid service() {
       while (true) {
           Socket socket = null;
           try {
              socket = serverSocket.accept(); // 等待客户连接
              System.out.println("New connection accepted "
                     + socket.getInetAddress() + ":" + socket.getPort());
              BufferedReader br = getReader(socket);
              PrintWriter pw = getWriter(socket);
              String msg = null;
              while ((msg = br.readLine()) != null) {
                  System.out.println(msg);
                  pw.println(echo(msg));
                  if (msg.equals("bye")) // 如果客户发送的消息为“bye”,就结束通信
                     break;
              }
           } catch (IOException e) {
              e.printStackTrace();
           } finally {
              try {
                  if (socket != null)
                     socket.close(); // 断开连接
              } catch (IOException e) {
                  e.printStackTrace();
              }
           }
       }
    }
    publicstaticvoid main(String args[]) throws IOException {
       new EchoServer().service();
    }
}

2.客户端
1.创建一个Socket对象,指定服务器端的地址和端口;

private String host = "localhost";
privateintport = 8000;
private Socket socket;
……
socket = new Socket(host, port);

这里作为客户端,它的端口是由操作系统随机产生的。

2.Socket类提供了getInputStream()方法和getOutputStream()方法。
InputStream socketIn = socket.getInputStream();
OutputStream socketOut = socket.getOutputStream();


源代码EchoClient.java
publicclass EchoClient {
    private String host = "localhost";
    privateintport = 8000;
    private Socket socket;
    public EchoClient() throws IOException {
       socket = new Socket(host, port);
    }
    publicstaticvoid main(String args[]) throws IOException {
       new EchoClient().talk();
    }
    private PrintWriter getWriter(Socket socket) throws IOException {
       OutputStream socketOut = socket.getOutputStream();
       returnnew PrintWriter(socketOut, true);
    }
    private BufferedReader getReader(Socket socket) throws IOException {
       InputStream socketIn = socket.getInputStream();
       returnnew BufferedReader(new InputStreamReader(socketIn));
    }
    publicvoid talk() throws IOException {
       try {
           BufferedReader br = getReader(socket);
           PrintWriter pw = getWriter(socket);
           BufferedReader localReader = new BufferedReader(
                  new InputStreamReader(System.in));
           String msg = null;
           while ((msg = localReader.readLine()) != null) {
              pw.println(msg);
              System.out.println(br.readLine());
              if (msg.equals("bye"))
                  break;
           }
       } catch (IOException e) {
           e.printStackTrace();
       } finally {
           try {
              socket.close();
           } catch (IOException e) {
              e.printStackTrace();
           }
       }
    }
}

3.关闭Socket
1.关闭Socket的代码;

try {
       ……
    } catch (IOException e) {
       e.printStackTrace();
    } finally {
       try {
           socket.close();
       } catch (IOException e) {
           e.printStackTrace();
       }
    }

Socket类提供3个状态测试方法。
-isClosed():如果Socket已经连接到远程主机,并且还没有关闭,则返回true;
-isConnected():如果Socket曾经连接到远程主机,则返回true;
-isBound():如果Socket已经与一个本地端口绑定,则返回true。

判断一个Socket对象当前是否处于连接状态,
Boolean isConnected = socket.isConnected() && !socket.isClosed();

2.处理关闭
(1)当进程A与进程B交换的是字符流,并且是一行一行地读写数据时,可以事先约定一个特殊的标志。

BufferedReader br = getReader(socket);
PrintWriter pw = getWriter(socket);
String msg = null;
while ((msg = br.readLine()) != null) {
    System.out.println(msg);
    pw.println(echo(msg));
    if (msg.equals("bye")) // 如果客户发送的消息为“bye”,就结束通信
       break;
}

(2)进程A先发送一个消息,告诉进程B所发送的正文长度,然后发送正文。进程B只要读取完该长度的数据就可以停止读数据。

(3)进程A发送完所有数据后,关闭Socket。当进程B读入进程A发送的所有数据后,再次执行输入流的read()方法时,该方法返回-1.

InputStream socketIn = socket.getInputStream();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
byte[] buff = newbyte[1024];
int len = -1;
while ((len = socketIn.read(buff)) != -1) {
    buffer.write(buff, 0, len);
}
System.out.println(new String(buffer.toByteArray()));

(4)当调用Socket的close()方法关闭Socket时,它的输入流和输出流都被关闭。如果仅仅希望关闭输入或输出流其中之一,可调用半关闭方法:shutdownInput()和shutdownOutput()。先后调用Socket的shutdownInput()和shutdownOutput()方法,仅仅关闭输入流和输出流,并不等价于调用close()方法。在通信结束后仍然需要调用close()方法,因为该方法才会释放Socket占用的资源。

4.多线程服务器
EchoServer只能顺序的处理Client端的请求,这里使用ExecutorService指定一个线程池用于处理连接请求。

private ExecutorService executorService; // 线程池
privatefinalintPOOL_SIZE = 4; // 单个CPU时线程池中工作线程的数目
…….
executorService = Executors.newFixedThreadPool(Runtime.getRuntime()
              .availableProcessors()* POOL_SIZE);
……
try {
       socket = serverSocket.accept();
       executorService.execute(new Handler(socket));
    } catch (IOException e) {
       e.printStackTrace();
    }

Hander类封装了原来处理连接请求的逻辑,只要当前线程池中有空闲的线程,就可以用于处理请求。

源代码MultiEchoServer.java
publicclass MultiEchoServer {
    privateintport = 8000;
    private ServerSocket serverSocket;
    private ExecutorService executorService; // 线程池
    privatefinalintPOOL_SIZE = 4; // 单个CPU时线程池中工作线程的数目
    public MultiEchoServer() throws IOException {
       serverSocket = new ServerSocket(port);
       executorService = Executors.newFixedThreadPool(Runtime.getRuntime()
              .availableProcessors()
              * POOL_SIZE);
       System.out.println("Server Start");
    }
    publicvoid service() {
       while (true) {
           Socket socket = null;
           try {
              socket = serverSocket.accept();
              executorService.execute(new Handler(socket));
           } catch (IOException e) {
              e.printStackTrace();
           }
       }
    }
    publicstaticvoid main(String args[]) throws IOException {
       new MultiEchoServer().service();
    }
}
class Handler implements Runnable {
    private Socket socket;
    public Handler(Socket socket) {
       this.socket = socket;
    }
    private PrintWriter getWriter(Socket socket) throws IOException {
       OutputStream socketOut = socket.getOutputStream();
       returnnew PrintWriter(socketOut, true);
    }
    private BufferedReader getReader(Socket socket) throws IOException {
       InputStream socketIn = socket.getInputStream();
       returnnew BufferedReader(new InputStreamReader(socketIn));
    }
    public String echo(String msg) {
       return"echo:" + msg;
    }
    publicvoid run() {
       try {
           System.out.println("New connection accepted "
                  + socket.getInetAddress() + ":" + socket.getPort());
           BufferedReader br = getReader(socket);
           PrintWriter pw = getWriter(socket);
           String msg = null;
           while ((msg = br.readLine()) != null) {
              System.out.println(msg);
              pw.println(echo(msg));
              if (msg.equals("bye"))
                  break;
           }
       } catch (IOException e) {
           e.printStackTrace();
       } finally {
           try {
              if (socket != null)
                  socket.close();
           } catch (IOException e) {
              e.printStackTrace();
           }
       }
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

日霄科技

感谢各位大佬,您鼓励是我的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值