之前在工作中写过一些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. CLR Via C#: CLR 的执行模型

    CLR(Common Language Runtime)公共语言运行时:是一个可由多种编程语言使用的“运行时”. 编译源代码文件的过程: C# 源代码文件 -> C# 编译器->托管模块( ...

  2. Leetcode初级算法(字符串篇)

    目录 反转字符串 颠倒整数 字符串中的第一个唯一字符 有效的字母异位词 验证回文字符串 实现strStr() 数数并说 最长公共前缀 字符串转整数(atoi) 反转字符串 和vector同样的进行sw ...

  3. ubuntu下ganglia3.7.2编译安装

    一.介绍 ganglia主要包括gmond和gmeta 1.gmond用于收集监测数据,可以发送也可以接收在同一个组播或单播通道上的统计信息.gmond有两个角色,一个是发送者,另一个是接收者.当mu ...

  4. Java中keytool管理证书

    1.创建证书库以及第一个证书 keytool -genkeypair -alias "wangpass" -keyalg "RSA" -keystore &qu ...

  5. Django 04 模板标签(if、for、url、with、autoeacape、模板继承于引用、静态文件加载)

    Django 04 模板标签(if.for.url.with.autoeacape.模板继承于引用.静态文件加载) 一.if.for.url.with.autoescape urlpatterns = ...

  6. JS——制作简单的网页计算器

    用JS做了一个简易的网页计算器 <!DOCTYPE html> <html lang="en"> <head> <meta charset ...

  7. Telerik RadPropertyGrid 设置显隐 Combox选择

    Telerik RadPropertyGrid 的排序按钮.搜索框和描述面板的显隐只要设置SortAndGroupButtons.SearchBox.DescriptionPanel的属性值改为Vis ...

  8. python学习三(数据保存到文件)

    以写模式打开文件:需要指定写模式,如下所示 data = open('data.out','w') 如果文件已经存在,则会清空它现有的所有内容.要追加一个文件,需要使用访问模式a,会追加到下一行. 例 ...

  9. Linux中vim编辑器常用操作技巧

    Normal 0 false false false EN-US ZH-CN X-NONE /* Style Definitions */ table.MsoNormalTable {mso-styl ...

  10. Java微信公众平台开发(十)--微信用户信息的获取

    前面的文章有讲到微信的一系列开发文章,包括token获取.菜单创建等,在这一篇将讲述在微信公众平台开发中如何获取微信用户的信息,在上一篇我们有说道微信用户和微信公众账号之间的联系可以通过Openid关 ...