java中處理socket通信過(guò)程中粘包的情況
這兩天學(xué)習(xí)了java中處理socket通信過(guò)程中粘包的情況,而且很重要,所以,今天添加一點(diǎn)小筆記。
處理粘包程序是客戶端的接受消息線程:
客戶端:
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Reader;
import java.net.Socket;
import java.nio.CharBuffer;
public class TestSocketClient {
public static void main(String[] args) {
// TODO Auto-generated method stub
new TestSocketClient().start();
}
class SendThread extends Thread{
private Socket socket;
public SendThread(Socket socket){
this.socket=socket;
}
@Override
public void run(){
while(true){
try{
Thread.sleep(1000);
String send="<SOAP-ENV:Envelope>"+System.currentTimeMillis()+"</SOAP-ENV:Envelope>";
PrintWriter pw=new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
pw.write(send);
pw.flush();
}catch(Exception e){
e.printStackTrace();
}
}
}
}
class ReceiveThread extends Thread{
private Socket socket;
private volatile byte[] bytes=new byte[0];
public ReceiveThread(Socket socket){
this.socket=socket;
}
public byte[] mergebyte(byte[] a,byte[] b,int begin,int end){
byte[] add=new byte[a.length+end-begin];
int i=0;
for(i=0;i<a.length;i++){
add[i]=a[i];
}
for(int k=begin;k<end;k++,i++){
add[i]=b[k];
}
return add;
}
@Override
public void run(){
while(true){
try{
InputStream reader=socket.getInputStream();
if(bytes.length<2){
byte[] head=new byte[2-bytes.length];
int couter=reader.read(head);
if(couter<0){
continue;
}
bytes=mergebyte(bytes,head,0,couter);
if(couter<2){
continue;
}
}
//下面這個(gè)值請(qǐng)注意,一定要取2長(zhǎng)度的字節(jié)子數(shù)組作為報(bào)文長(zhǎng)度,你懂得
byte[] temp=new byte[0];
temp=mergebyte(temp,bytes,0,2);
String templength=new String(temp);
int bodylength=Integer.parseInt(templength);
if(bytes.length-2<bodylength){
byte[] body=new byte[bodylength+2-bytes.length];
int couter=reader.read(body);
if(couter<0){
continue;
}
bytes=mergebyte(bytes,body,0,couter);
if(couter<body.length){
continue;
}
}
byte[] body=new byte[0];
body=mergebyte(body, bytes, 2, bytes.length);
System.out.println("client receive body: "+new String(body));
bytes=new byte[0];
}catch(Exception e){
e.printStackTrace();
}
}
}
}
public void start(){
try{
Socket socket=new Socket("127.0.0.1",18889);
new SendThread(socket).start();
new ReceiveThread(socket).start();
}catch(Exception e){
e.printStackTrace();
}
}
}
服務(wù)端:
package com.meituan.service.bankgate.gateway;
/**
* Created by cqx on 16/7/19.
*/
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.CharBuffer;
import java.util.Date;
public class TESTAHAHHA {
private final static String SOAP_BEGIN = "<SOAP-ENV:Envelope";
private final static String SOAP_END = "</SOAP-ENV:Envelope>";
public static void main(String[] args) {
// TODO Auto-generated method stub
TESTAHAHHA testserver=new TESTAHAHHA();
testserver.start();
}
public void start(){
try{
ServerSocket serversocket=new ServerSocket(18889);
while(true){
Socket socket=serversocket.accept();
new SocketThread(socket).start();
}
}catch(Exception e){
e.printStackTrace();
}
}
class SocketThread extends Thread{
private Socket socket;
private String temp;
public SocketThread(Socket socket){
this.socket=socket;
}
public Socket getsocket(){
return this.socket;
}
public void setsocjet(Socket socket){
this.socket=socket;
}
@Override
public void run(){
try{
Reader reader=new InputStreamReader(socket.getInputStream());
// Writer writer=new PrintWriter(new OutputStreamWriter(socket.getOutputStream(),"UTF-8"));
OutputStream writer=socket.getOutputStream();
CharBuffer charbuffer=CharBuffer.allocate(8192);
int readindex=-1;
while((readindex=reader.read(charbuffer))!=-1){
charbuffer.flip();
temp+=charbuffer.toString();
if(temp.indexOf(SOAP_BEGIN)!=-1 && temp.indexOf(SOAP_END)!=-1){
//System.out.println(new Date().toLocaleString()+"server:"+temp);
temp="";
String str="receive the soap message hahahah";
byte[] headbytes=str.getBytes();
int length=headbytes.length;
String l=String.valueOf(length);
byte[] lengthbytes=l.getBytes();
byte[] bytes=new byte[length+lengthbytes.length];
int i=0;
for(i=0;i<lengthbytes.length;i++){
bytes[i]=lengthbytes[i];
}
for(int j=i,k=0;k<length;k++,j++){
bytes[j]=headbytes[k];
}
System.out.println("server send:"+new String(bytes));
writer.write(bytes);
writer.flush();
}else if(temp.indexOf(SOAP_BEGIN)!=-1){
temp=temp.substring(temp.indexOf(SOAP_BEGIN));
}
if(temp.length()>1024*16){
break;
}
}
}catch(Exception e){
e.printStackTrace();
}finally{
if(socket!=null){
try{
if(!socket.isClosed()){
socket.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}
}
}
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Java Web項(xiàng)目中使用Socket通信多線程、長(zhǎng)連接的方法
- Java實(shí)現(xiàn)的基于socket通信的實(shí)例代碼
- php與java通過(guò)socket通信的實(shí)現(xiàn)代碼
- JAVA實(shí)現(xiàn)基于Tcp協(xié)議的簡(jiǎn)單Socket通信實(shí)例
- Python與Java間Socket通信實(shí)例代碼
- Java Socket實(shí)現(xiàn)多線程通信功能示例
- Java--Socket通信(客戶端服務(wù)端雙向)
- JAVA中實(shí)現(xiàn)原生的 socket 通信機(jī)制原理
- Java使用Socket通信傳輸文件的方法示例
- Java Socket實(shí)現(xiàn)單線程通信的方法示例
- Java開(kāi)發(fā)實(shí)現(xiàn)的Socket雙向通信功能示例
相關(guān)文章
Java使用JDBC或MyBatis框架向Oracle中插入XMLType數(shù)據(jù)
XMLType是Oracle支持的一種基于XML格式存儲(chǔ)的數(shù)據(jù)類型,這里我們共同來(lái)探究Java使用JDBC或MyBatis框架向Oracle中插入XMLType數(shù)據(jù)的方法:2016-07-07
JAVA中通過(guò)Redis實(shí)現(xiàn)延時(shí)任務(wù)demo實(shí)例
Redis在2.0版本時(shí)引入了發(fā)布訂閱(pub/sub)功能,在發(fā)布訂閱中有一個(gè)channel(頻道),與消息隊(duì)列中的topic(主題)類似,可以通過(guò)redis的發(fā)布訂閱者模式實(shí)現(xiàn)延時(shí)任務(wù)功能,實(shí)例中會(huì)議室預(yù)約系統(tǒng),用戶預(yù)約管理員審核后生效,如未審批,需要自動(dòng)變超期未處理,使用延時(shí)任務(wù)2024-08-08
Spring Boot thymeleaf模板引擎的使用詳解
這篇文章主要介紹了Spring Boot thymeleaf模板引擎的使用詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03
springboot項(xiàng)目中idea的pom.xml文件的引用標(biāo)簽全部爆紅問(wèn)題解決
這篇文章主要介紹了springboot項(xiàng)目中idea的pom.xml文件的引用標(biāo)簽全部爆紅問(wèn)題解決,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),需要的朋友參考下吧2023-12-12
Java如何利用return結(jié)束方法調(diào)用
這篇文章主要介紹了Java如何利用return結(jié)束方法調(diào)用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02
lazy?init控制加載在Spring中如何實(shí)現(xiàn)源碼分析
這篇文章主要為大家介紹了lazy?init控制加載在Spring中如何實(shí)現(xiàn)源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
Mybatis的sql語(yǔ)句執(zhí)行異常后打印到日志問(wèn)題
文章介紹了一種Mybatis異常日志打印方案,主要通過(guò)Mybatis攔截器獲取執(zhí)行的sql語(yǔ)句,并利用ThreadLocal存儲(chǔ),以避免多線程下的sql語(yǔ)句覆蓋問(wèn)題,當(dāng)異常發(fā)生時(shí),從ThreadLocal中取出sql語(yǔ)句并打印到單獨(dú)的日志文件中,方便數(shù)據(jù)恢復(fù),該方案經(jīng)過(guò)壓力測(cè)試2024-10-10

