本来是打算验证java socket是不是单线程操作,也就是一次只能处理一个请求,处理完之后才能继续处理下一个请求。但是在其中又发现了许多问题,在编程的时候需要十分注意,今天就拿出来跟大家分享一下。

首先先建立一个服务端代码,运行时也要先启动此程序。

package com.test.some.Socket;

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException; /**
* @Description: socket服务端代码
* @Author: haoqiangwang3
* @CreateDate: 2020/1/9
*/
public class MySocketServer1 {
// 服务器监听端口
private static int port = 8081; public static void main(String[] args) throws InterruptedException {
try {
//1.得到一个socket服务端
ServerSocket serverSocket = new ServerSocket(port);
while (true) { // 2.等待socket客户端的请求。accept方法在有连接请求时才会返回
System.out.println("等待客户端请求。。。");
Socket socket = serverSocket.accept();
System.out.println("客户端请求来了。。。"); // 3.获取socket输入流
InputStream inputStream = socket.getInputStream();
/* BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
System.out.println("接收到的请求数据为:" + bufferedReader.readLine());*/
// 读取请求内容的缓冲区
byte[] bytes = new byte[1024];
int length = 0;
StringBuilder sb = new StringBuilder();
//获取客户端请求的内容
while ((length = inputStream.read(bytes)) != -1) {
sb.append(new String(bytes, 0, length, "utf-8"));
}
System.out.println("接收到的请求数据为:" + sb.toString());          
          //Thread.sleep(50000);

          // 4.获取socket输出流
OutputStream outputStream = socket.getOutputStream();
PrintWriter printWriter = new PrintWriter(outputStream);
String backStr = "服务端接收到了请求";
printWriter.write(new String(backStr.getBytes(), "utf-8"));
printWriter.flush(); //5.关闭资源
//bufferedReader.close();
inputStream.close();
printWriter.close();
outputStream.close();
socket.close();
} } catch (IOException e) {
System.err.println("socket监听失败!" + e);
}
} }

此代码模拟了正常系统成socket服务端的方式,就是一个无限循环监听我们绑定的端口,当有客户端请求来了之后进行处理。

下面就是客户端请求代码

package com.test.some.Socket;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket; /**
* @Description: socket客户端代码
* @Author: haoqiangwang3
* @CreateDate: 2020/1/9
*/
public class MySocketClient1 {
//socket请求ip地址
private static String host = "127.0.0.1"; //socket请求端口
private static int port = 8081; public static void main(String[] args) {
try {
//1.建立一个客户端
Socket socket = new Socket(host, port); //2.得到socket输出流
OutputStream outputStream = socket.getOutputStream();
PrintWriter printWriter = new PrintWriter(outputStream);
String sendStr = "发送数据1";
//发送数据
printWriter.write(sendStr);
printWriter.flush();
socket.shutdownOutput(); //3.得到socket输入流
InputStream inputStream = socket.getInputStream();
StringBuilder sb = new StringBuilder();
byte[] bytes = new byte[1024];
while (inputStream.read(bytes) != -1) {
sb.append(new String(bytes, "utf-8"));
}
System.out.println("接收到的返回数据为:" + sb); //4.关闭资源
printWriter.close();
outputStream.close();
inputStream.close();
socket.close();
} catch (Exception e) {
System.err.println("socket请求失败" + e);
}
} }

客户端代码主要就是向服务端发送数据,然后等待服务端的响应,打印出服务端的响应内容。

最终打印结果如下。服务端:

客户端:


首先明确几个概念,下面将会用到。

flush()方法:用于清空缓冲区的数据流,进行流的操作时,数据先被读到内存缓冲区中,然后再用数据写到文件中。

socket.shutdownOutput()方法:他是一种单向关闭流的方法,即关闭客户端的输出流并不会关闭服务端的输出流。通过shutdownOutput()方法只是关闭了输出流,但socket仍然是连接状态,连接并未关闭。

printWriter.close()方法:如果直接关闭输入或者输出流,即:in.close()或者out.close(),会直接关闭socket。

流中的关闭顺序:一般情况下是:先打开的后关闭,后打开的先关闭。另一种情况:看依赖关系,如果流a依赖流b,应该先关闭流a,再关闭流b,例如处理流a依赖节点流b,应该先关闭处理流a,再关闭节点流b。当然完全可以只关闭处理流,不用关闭节点流。处理流关闭的时候,会调用其处理的节点流的关闭方法。如果将节点流关闭以后再关闭处理流,会抛出IO异常。

下面总结下我遇到的问题。

1.客户端发送数据部分的代码,printWriter.flush(); socket.shutdownOutput(); 这两句代码十分的重要,flush()方法如果不添加的话,服务端接收到的数据将为空,shutdownOutput()方法不添加的话,服务端将一直等待读取客户端的数据,不会往下进行,大家可以自测一下。我自己的理解是flush()的作用是为了把数据从内存中刷新到socket流中,shutdownOutput()方法是告诉服务端,我没有东西要传输了,所以服务端也就会停止等待读取客户端发送的内容,程序就可以继续向下走。

2.打开服务端中的sleep方法,在新建一个客户端,同时开启请求服务端,会发现服务端确实是一个连接一个连接的处理,所以这也是socket性能所在的问题。

3.如果不用字符流读取,客户端发送数据直接用outputStream.write(sendStr.getBytes());,可以发现此时不用调用flush()方法,但是socket.shutdownOutput()依然需要。这是因为直接读取到socket的输出流,并没有读到内存中。

java socket通讯的更多相关文章

  1. java socket通讯(二)处理多个客户端连接

    通过java socket通讯(一) 入门示例,就可以实现服务端和客户端的socket通讯,但是上一个例子只能实现一个服务端和一个客户端之间的通讯,如果有多个客户端连接服务端,则需要通过多线程技术来实 ...

  2. Java Socket通讯---网络基础

    java socket 通讯 参考慕课网:http://www.imooc.com/learn/161 一.网络基础知识 1.1 通讯示意图 1.2 TCP/IP协议 TCP/IP是世界上应用最为广泛 ...

  3. java socket通讯(一) 入门示例

    一.入门 要想学习socket通讯,首先得知道tcp/ip和udp连接,具体可参考浅谈TCP/IP 和 UDP的区别 二.示例 首先新建了一个java工程,包括两个部分,客户端SocketClient ...

  4. java socket 通讯

    (转)http://blog.csdn.net/xn4545945/article/details/8098646

  5. Socket网络通讯开发总结之:Java 与 C进行Socket通讯 + [备忘] Java和C之间的通讯

    Socket网络通讯开发总结之:Java 与 C进行Socket通讯 http://blog.sina.com.cn/s/blog_55934df80100i55l.html (2010-04-08 ...

  6. Socket网络通讯开发总结之:Java 与 C进行Socket通讯(转)

    先交待一下业务应用背景:服务端:移动交费系统:基于C语言的Unix系统客户端:增值服务系统:基于Java的软件系统通迅协议:采用TCP/IP协议,使用TCP以异步方式接入数据传输:基于Socket流的 ...

  7. java socket 多线程通讯 使用mina作为服务端

    客户端代码不变,参照 http://www.cnblogs.com/Westfalen/p/6251473.html 服务端代码如下: import java.io.IOException; impo ...

  8. Socket通讯-Netty框架实现Java通讯

    Netty简介 Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客户端程序. 也就是说,Netty ...

  9. java与C++之间进行SOCKET通讯要点简要解析

    原文链接: http://blog.csdn.net/hslinux/article/details/6214594 java与C++之间进行SOCKET通讯要点简要解析 hslinux 0.篇外语 ...

随机推荐

  1. oracle 基础表的选择

    基础表(Driving Table)是指被最先访问的表(通常以全表扫描的方式被访问). 根据优化器的不同, SQL语句中基础表的选择是不一样的. 如果你使用的是CBO (COST BASED OPTI ...

  2. laravel中将session由文件保存改为数据库保存

    1.laravel中默认是使用文件保存session的,保存在/storage/framework/sessions下 2.修改配置文件 config/session.php中 'driver' =& ...

  3. pytorch实现BiLSTM+CRF用于NER(命名实体识别)

    pytorch实现BiLSTM+CRF用于NER(命名实体识别)在写这篇博客之前,我看了网上关于pytorch,BiLstm+CRF的实现,都是一个版本(对pytorch教程的翻译), 翻译得一点质量 ...

  4. vue用法父组件调用子组件方法--->$refs

    vue下载excel模板(放入弹框独立出来)后再导入表格 子组件 <el-dialog title="导入" :visible.sync="dialogVisibl ...

  5. ant 脚本 available 及条件判断功能

    1. 通过<available property="属性名"  file | classname | resource = "被判定是否存在的东西"  v ...

  6. P1095 水仙花数

    题目描述 春天是鲜花的季节,水仙花就是其中最迷人的代表,数学上有个水仙花数,他是这样定义的:"水仙花数"是指一个三位数,它的各位数字的立方和等于其本身,比如:153=1^3+5^3 ...

  7. java 文件过滤器 java.io.FilenameFilter

    File 类里有方法: String[] list(FilenameFilter filter)    返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录. File ...

  8. linux预备知识

    我们正在接近去看一些实际的模块代码. 但是首先, 我们需要看一些需要出现在你的模块 源码文件中的东西. 内核是一个独特的环境, 它将它的要求强加于要和它接口的代码上. 大部分内核代码包含了许多数量的头 ...

  9. vue-learning:6-template-v-bind

    绑定元素特性的指令v-bind 回顾下,从HTML元素的结构看,在VUE框架中,内容由插值{{ }}和v-html绑定:v-if和v-show可以控制元素的可见性:v-for可以用于批量生成列表元素. ...

  10. PowerShell 通过 WMI 获取系统信息

    本文告诉大家如何通过 WMI 使用 Win32_OperatingSystem 获取设备厂商 通过下面代码可以获取 系统版本和系统是专业版还是教育版 Get-WmiObject Win32_Opera ...