之前在工作中写过一些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)的更多相关文章

  1. 实现Java Socket 客户端服务端交互实例

    SocketService.java package socket; import java.io.BufferedReader; import java.io.IOException; import ...

  2. Java Socket 服务端发送数据 客户端接收数据

    服务端: package com.thinkgem.wlw.modules.api.test.socket; /** * @Author: zhouhe * @Date: 2019/4/8 9:30 ...

  3. java socket 服务端 客户端

    Server package com.witwicky.socket.basicsocket; import java.io.IOException; import java.io.InputStre ...

  4. java scoket客户端服务端发送消息

    客户端 public class User { public static void main(String[] args) { while (true) { try { Socket socket ...

  5. java Socket通信,客户端与服务端相互发消息

    1.通信过程 网络分为应用层,http.ssh.telnet就是属于这一类,建立在传输层的基础上.其实就是定义了各自的编码解码格式,分层如下: 2.Socket连接 上述通信都要先在传输层有建立连接的 ...

  6. java Socket Tcp示例三则(服务端处理数据、上传文件)

    示例一: package cn.itcast.net.p5.tcptest; import java.io.BufferedReader;import java.io.IOException;impo ...

  7. Java Socket IO(BIO、NIO)

    总结下Java socket IO.首先是各种IO的定义,这个定义似乎也是众说纷纭.我按照stackoverflow上面的解释: IO有两种分法:按照阻塞或者按照同步.按照阻塞,有阻塞IO和非阻塞IO ...

  8. Java中使用Socket连接判断Inputstream结束,java tcp socket服务端,python tcp socket客户端

    最近在试着用java写一个socket的服务器,用python写一个socket的客户端来完成二者之间的通信,但是发现存在一个问题,服务器方面就卡在读取inputsream的地方不动了,导致后面的代码 ...

  9. 【Socket】Java Socket基础编程

    Socket是Java网络编程的基础,了解还是有好处的, 这篇文章主要讲解Socket的基础编程.Socket用在哪呢,主要用在进程间,网络间通信.本篇比较长,特别做了个目录: 一.Socket通信基 ...

随机推荐

  1. css 实现三级联动菜单

    昨天因为项目中想要把二级联动菜单改成三级联动菜单,所以我就单独写了一个tab导航栏,用纯css的方式实现的三级联动.一开始我想着可以用js实现,但是js的hover事件和mouseenter,mous ...

  2. Redis数据类型,持久化,回收策略——(Redis缓存第一章)

    缓存:第一种是内存缓存 比如Map(简单的数据结构),以及EH Cache(Java第三方库),第二种是缓存组件比如Memached,Redis:Redis(remote dictionary ser ...

  3. spring boot——MockMvc的用法 (SpringBoot 1.5.18)下测试通过

    spring boot——MockMvc的用法   1.pom配置 <dependency> <groupId>org.springframework.boot</gro ...

  4. 爱上MVC~业务层刻意抛出异常,全局异常的捕获它并按格式返回

    回到目录 对于业务层的程序的致命错误,我们一直的做法就是直接抛出指定的异常,让程序去终断,这种做法是对的,因为如果一个业务出现了致命的阻塞的问题,就没有必要再向上一层一层的返回了,但这时有个问题,直接 ...

  5. javaweb项目导入myecplise出错

    项目导入出错:移动项目的时候.classpath .project不要删 build path -> use for source floder 把某一文件夹当作源码文件夹 bulid path ...

  6. 白话SpringCloud | 第零章:前言

    说在前面 大清早醒来,觉得睡不着了.还是起来,写写博客.但最后发现关于SpringBoot的安全相关的还是比较多内容的,也比较专业,怕是一个多小时完不成的,也罢,那就来写写关于SpringCloud前 ...

  7. Windows下使用nvm管理多个Node.js 版本

    下载 https://github.com/coreybutler/nvm-windows/releases 安装       配置 使用 # nvm install 版本号   # nvm list ...

  8. asp.net MVC 中枚举创建下拉列表?

    我将尝试使用 Html.DropDownList 扩展方法,但不能找出如何使用它的枚举. 让我们说我有一个这样的枚举: public enum ItemTypes { Movie = 1, Game ...

  9. Elasticsearch在后台启动

    Elasticsearch在linux下使用命令sh elasticsearch start,按键ctrl+c的时候程序就会stop掉,如何将程序在后台启动呢? 需要使用:./elasticsearc ...

  10. DockerSwarm 微服务部署

    一.简介 之前<服务Docker化>中,使用 docker-compose.yml 来一次配置启动多个容器,在 Swarm 集群中也可以使用 compose 文件 (docker-comp ...