Java socket通讯实现过程及问题解决
这篇文章主要介绍了Javasocket通讯实现过程及问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
本来是打算验证javasocket是不是单线程操作,也就是一次只能处理一个请求,处理完之后才能继续处理下一个请求。但是在其中又发现了许多问题,在编程的时候需要十分注意,今天就拿出来跟大家分享一下。
首先先建立一个服务端代码,运行时也要先启动此程序。
packagecom.test.some.Socket;
importjava.io.*;
importjava.net.InetAddress;
importjava.net.ServerSocket;
importjava.net.Socket;
importjava.net.UnknownHostException;
/**
*@Description:socket服务端代码
*@Author:haoqiangwang3
*@CreateDate:2020/1/9
*/
publicclassMySocketServer1{
//服务器监听端口
privatestaticintport=8081;
publicstaticvoidmain(String[]args)throwsInterruptedException{
try{
//1.得到一个socket服务端
ServerSocketserverSocket=newServerSocket(port);
while(true){
//2.等待socket客户端的请求。accept方法在有连接请求时才会返回
System.out.println("等待客户端请求。。。");
Socketsocket=serverSocket.accept();
System.out.println("客户端请求来了。。。");
//3.获取socket输入流
InputStreaminputStream=socket.getInputStream();
/*BufferedReaderbufferedReader=newBufferedReader(newInputStreamReader(inputStream));
System.out.println("接收到的请求数据为:"+bufferedReader.readLine());*/
//读取请求内容的缓冲区
byte[]bytes=newbyte[1024];
intlength=0;
StringBuildersb=newStringBuilder();
//获取客户端请求的内容
while((length=inputStream.read(bytes))!=-1){
sb.append(newString(bytes,0,length,"utf-8"));
}
System.out.println("接收到的请求数据为:"+sb.toString());
//Thread.sleep(50000);//4.获取socket输出流
OutputStreamoutputStream=socket.getOutputStream();
PrintWriterprintWriter=newPrintWriter(outputStream);
StringbackStr="服务端接收到了请求";
printWriter.write(newString(backStr.getBytes(),"utf-8"));
printWriter.flush();
//5.关闭资源
//bufferedReader.close();
inputStream.close();
printWriter.close();
outputStream.close();
socket.close();
}
}catch(IOExceptione){
System.err.println("socket监听失败!"+e);
}
}
}
此代码模拟了正常系统成socket服务端的方式,就是一个无限循环监听我们绑定的端口,当有客户端请求来了之后进行处理。
下面就是客户端请求代码
packagecom.test.some.Socket;
importjava.io.InputStream;
importjava.io.OutputStream;
importjava.io.PrintWriter;
importjava.net.Socket;
/**
*@Description:socket客户端代码
*@Author:haoqiangwang3
*@CreateDate:2020/1/9
*/
publicclassMySocketClient1{
//socket请求ip地址
privatestaticStringhost="127.0.0.1";
//socket请求端口
privatestaticintport=8081;
publicstaticvoidmain(String[]args){
try{
//1.建立一个客户端
Socketsocket=newSocket(host,port);
//2.得到socket输出流
OutputStreamoutputStream=socket.getOutputStream();
PrintWriterprintWriter=newPrintWriter(outputStream);
StringsendStr="发送数据1";
//发送数据
printWriter.write(sendStr);
printWriter.flush();
socket.shutdownOutput();
//3.得到socket输入流
InputStreaminputStream=socket.getInputStream();
StringBuildersb=newStringBuilder();
byte[]bytes=newbyte[1024];
while(inputStream.read(bytes)!=-1){
sb.append(newString(bytes,"utf-8"));
}
System.out.println("接收到的返回数据为:"+sb);
//4.关闭资源
printWriter.close();
outputStream.close();
inputStream.close();
socket.close();
}catch(Exceptione){
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的输出流,并没有读到内存中。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。