java Socket 客户端服务端对接正确写法(BIO)
之前在工作中写过一些Socket客户端与服务端的代码,但是当时没有时间仔细研究,只能不报错先过的态度,对其细节了解不深,写的代码有各种问题也浑然不知,只是业务量级以及对接方对接代码没有出现出格的情况所以问题不得暴露。
首先通过单线程Socket做服务端是一种BIO的做法,这种做法会导致服务端只能同时接收一笔请求,性能非常差
下面我把BIO的代码帖一下,有需要的同学可以参考
服务端
public class SocketIO {
//客户端编码,客户端发送编码与服务端一致,则服务端无需进行解码特殊处理
private static final String CLIENTENCODEING = "UTF-8";
private static final int PORT = 7777;
private static AtomicInteger count = new AtomicInteger();
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(PORT);
System.out.println("端口启动:"+PORT);
while (true) {
Socket socket = null;
InputStream inputStream = null;
OutputStream outputStream = null;
try {
//无数据时会阻塞在这里,有数据即accept事件会触发accept方法的调用
//当一个连接进来,第二个连接进不来,因为单线程时,还阻塞在下面的read,线程无法再回到accept上继续等待
socket = serverSocket.accept();
int ccount = count.incrementAndGet();
System.out.println("新的客户端已连接,当前No."+ccount+" "+System.currentTimeMillis());
inputStream = new BufferedInputStream(socket.getInputStream());
outputStream = new BufferedOutputStream(socket.getOutputStream());
//读取正文内容
byte[] flush = new byte[1024];
int length = 0;
StringBuffer rec = new StringBuffer();
while ((length = inputStream.read(flush)) != -1) {
rec.append(new String(flush, 0, length));
}
//写法2
//客户端不通知关闭socket.shutdownOutput();时,用下面这种方法,不通知关闭read方法会死循环
//available()方法可以在读写操作前先得知数据流里有多少个字节可以读取
//但如果客户端分批发送可能有问题,可能无法获得第二批及以后的数据
//所以最好还是让客户端通知一下
// int count = 0;
// while(count == 0){
// count = inputStream.available();
// }
// byte[] flush = new byte[count];
// inputStream.read(flush);
// String rec = new String(flush, 0, count, CLIENTENCODEING);
String back = "["+ccount+"]"+UUID.randomUUID() + "";
System.out.println("收到数据:" + rec.toString() + " 即将返回数据:" + back);
//返回数据
outputStream.write(back.getBytes(), 0, back.getBytes().length);
outputStream.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
close(socket,inputStream,outputStream);
}
}
}
private static void close(Socket socket,
InputStream inputStream,
OutputStream outputStream) throws IOException {
if (outputStream != null) {
outputStream.close();
}
if (inputStream != null) {
inputStream.close();
}
if (socket != null) {
socket.close();
}
}
}
列几点需要注意的点:
1、最好通过read方法来读取客户端发来的内容,代码中available我实测客户端发送多次的情况下会丢消息,不可靠。
2、最好通过缓冲流Buffered*Stream来配合InputStream、OutputStream使用
3、write后记得flush
4、关闭流
客户端
//服务端编码
private static final String SERVERENCODEING = "UTF-8"; public static void main(String[] args){
for (int i = 0; i < 1; i++) {
new Thread(() -> {
try {
doo();
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
} public static void doo() throws IOException {
Socket socket = null;
InputStream in = null;
OutputStream out = null;
String msg = "你好你好你好好好!";
try {
//发送数据
socket = new Socket("127.0.0.1", 7777);
out = new BufferedOutputStream(socket.getOutputStream());
in = new BufferedInputStream(socket.getInputStream());
out.write(msg.getBytes());
out.flush(); out.write("还有点".getBytes());
out.flush();
// //任何的输入流或输出流的close()都会造成Socket关闭 但是不关闭又导致服务端无法接收到-1
// out.close();
socket.shutdownOutput(); //读取正文内容
byte[] flush = new byte[1024];
int length = 0;
StringBuffer rec = new StringBuffer();
while ((length = in.read(flush)) != -1) {
rec.append(new String(flush, 0, length, SERVERENCODEING));//以服务端编码标准发送
}
System.out.println("客户端收到回复:" + rec.toString());
in.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
close(socket, in, out);
}
} private static void close(Socket socket,
InputStream inputStream,
OutputStream outputStream) throws IOException {
if (outputStream != null) {
outputStream.close();
}
if (inputStream != null) {
inputStream.close();
}
if (socket != null) {
socket.close();
}
}
列几点需要注意的点:
1、out.close();任何的输入流或输出流的close()都会造成Socket关闭 但是不关闭又导致服务端无法接收到-1
2、使用socket.shutdownOutput();来通知服务端发送完成
3、write后记得flush
4、关闭流
java Socket 客户端服务端对接正确写法(BIO)的更多相关文章
- 实现Java Socket 客户端服务端交互实例
SocketService.java package socket; import java.io.BufferedReader; import java.io.IOException; import ...
- Java Socket 服务端发送数据 客户端接收数据
服务端: package com.thinkgem.wlw.modules.api.test.socket; /** * @Author: zhouhe * @Date: 2019/4/8 9:30 ...
- java socket 服务端 客户端
Server package com.witwicky.socket.basicsocket; import java.io.IOException; import java.io.InputStre ...
- java scoket客户端服务端发送消息
客户端 public class User { public static void main(String[] args) { while (true) { try { Socket socket ...
- java Socket通信,客户端与服务端相互发消息
1.通信过程 网络分为应用层,http.ssh.telnet就是属于这一类,建立在传输层的基础上.其实就是定义了各自的编码解码格式,分层如下: 2.Socket连接 上述通信都要先在传输层有建立连接的 ...
- java Socket Tcp示例三则(服务端处理数据、上传文件)
示例一: package cn.itcast.net.p5.tcptest; import java.io.BufferedReader;import java.io.IOException;impo ...
- Java Socket IO(BIO、NIO)
总结下Java socket IO.首先是各种IO的定义,这个定义似乎也是众说纷纭.我按照stackoverflow上面的解释: IO有两种分法:按照阻塞或者按照同步.按照阻塞,有阻塞IO和非阻塞IO ...
- Java中使用Socket连接判断Inputstream结束,java tcp socket服务端,python tcp socket客户端
最近在试着用java写一个socket的服务器,用python写一个socket的客户端来完成二者之间的通信,但是发现存在一个问题,服务器方面就卡在读取inputsream的地方不动了,导致后面的代码 ...
- 【Socket】Java Socket基础编程
Socket是Java网络编程的基础,了解还是有好处的, 这篇文章主要讲解Socket的基础编程.Socket用在哪呢,主要用在进程间,网络间通信.本篇比较长,特别做了个目录: 一.Socket通信基 ...
随机推荐
- 浏览器Quirksmode(怪异模式)与标准模式
由于历史的原因,各个浏览器在对页面的渲染上存在差异,甚至同一浏览器在不同版本中,对页面的渲染也不同.在W3C标准出台以前,浏览器在对页面的渲染上没有统一规范,产生了差异(Quirks mode或者称为 ...
- [USACO08JAN]跑步Running dp
题目描述 The cows are trying to become better athletes, so Bessie is running on a track for exactly N (1 ...
- 安居客scrapy房产信息爬取到数据可视化(下)-可视化代码
接上篇:安居客scrapy房产信息爬取到数据可视化(下)-可视化代码,可视化的实现~ 先看看保存的数据吧~ 本人之前都是习惯把爬到的数据保存到本地json文件, 这次保存到数据库后发现使用mongod ...
- gulp前端自动化构建工具
博主不易,不求赞赏,希望把自己遇到的难点写出来,以及希望自己能有能力写出一篇不错的博文. 前端构建工具本人 bootstrap+jquery用gulp vue+element 用webpack 引文 ...
- linux下find查找与批量替换文件中指定内容
经常在部署tomcat时需要替换配置文件中的ip,find命令批量替换还是很方便的 查找需要替换的ip,看看哪些文件有配置这个ip,执行下面命令: find ./ -type f -regex &qu ...
- C# DataTable转List<T>--利用反射
/// <summary> /// 利用反射将Datatable转换为List<T>对象 /// </summary> /// <typeparam name ...
- myeclipse非正常关闭解决方法
http://blog.csdn.net/xb12369/article/details/24960347
- spring框架详细课程视频
https://ke.qq.com/course/27346#term_id=100012852
- Ubuntu14.04下sogou输入法的输入框只显示英文不显示中文的问题
解决方法:首先强制更新,把依赖文件全部安装 sudo apt-get install -f 如果仍然不管用,删除sogou的配置文件,在~/.config目录下,一般情况下是SogouPY.Sogou ...
- 如何远程连接非默认端口SQL Server
SQL Server Management Studio建立远程SQL连接 连接的时候写: 127.0.0.1,49685\sqlexpress 记得使用逗号,不是冒号