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通信基 ...
随机推荐
- bzoj1412: [ZJOI2009]狼和羊的故事(最小割)
传送门 首先,考虑只有狼和羊怎么办.我们把源点向所有羊连边,容$inf$,所有狼向汇点连边,容$inf$,然后羊向周围所有的狼连边,容$1$.那么,只要求一个割就能把狼和羊给分开,求一个最小割就是答案 ...
- [Xcode 实际操作]三、视图控制器-(12)在Storyboard中使用集合控件
目录:[Swift]Xcode实际操作 本文将演示集合控件在故事板中的使用. 在控制器根视图上点击鼠标,以选择该根视图. 现在往根视图中添加一个集合视图. 点击[库面板]图标,打开控件库面板 在控件库 ...
- centos 基础设置
centos 6 关闭防火墙 查看防火墙是否开启 service iptables status 停止防火墙 service iptables stop 禁止开机自启动防火墙 chkconfig ip ...
- 使用jmeter往指定文件中插入一定数量的数据(转)
有一个需求,新建一批账号,把获取的账号相关信息存入文本文件,当文本文件保存的数据达到一定的数量,就自动停止新建账号. 分析下需求: 1.把账号信息保存到文件,需要使用bean shell脚本(bean ...
- linux环境下jdk部署配置
1.java官网下载相关的jdk包 2.配置系统环境变量,编辑/etc/profile文件,在文件的末尾添加一下信息: export JAVA_HOME=/usr/jdk1.8.0_101export ...
- Docker从入门到实战(二)
Docker从入门到实战(二) 一:什么是docker Docker是一个开源的应用容器引擎,开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到主流的Linux.MacOS.Windo ...
- PartTime_网址_国外
https://www.douban.com/group/topic/6248314/ 国外威客网站大全 国外兼职网站,以及国外外包网站.这些国外项目网站包括的项目类型很多:logo设计.图形设计.f ...
- strcpy、strncpy、strlen、memcpy、memset、strcat、strncat、strcmp、strncmp,strchr
1.strcpy #include<stdio.h> #include<assert.h> char *mystrcpy(char *dest, const char *src ...
- python操作json文件
import json class OperationJson(object): def __init__(self,file_name=None): if file_name: self.file_ ...
- Murano Weekly Meeting 2015.07.21
会议时间: 2015.07.21 主持人: Kirill Zaitsev, core from Mirantis 会议摘要: 1.murano client和murano dashboard升级到y ...