最近写Socket网络编程,服务器端接收数据老是不全。困扰了一个多星期,还以为是TCP的问题,后来找老大给我修改了一下程序。原因实际上还是我对TCP协议的运转机制不够熟悉,程序不够严谨。先把写好的程序贴在下面,以后有了感悟再在这个基础上修改,有问题大家也可以在下面留言给我。
客户端代码如下:
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class TCPClient{
public static void main(String[] args){
try {
Socket socket = new Socket("192.168.1.41",5500);
OutputStream outputStream = socket.getOutputStream();
byte[] b_data = new byte[75];
b_data[0]=0x01; //设备号
b_data[1]=0x00;
b_data[2]=0x00;
b_data[3]=0x00;
b_data[4]=0x01; //发送者标志
b_data[5]=0x02; //接受者标志
b_data[6]=0x02; //消息标志
b_data[7]=0x43; //消息长度
b_data[8]=0x01; //用户信息序号
b_data[9]=0x00;
b_data[10]=0x00;
b_data[11]=0x00;
b_data[12]=0x10; //消息类型
b_data[13]=0x3d; //参数长度
//参数
b_data[14]=0x33;
b_data[15]=0x0c;
b_data[16]=0x34; //IMSI
b_data[17]=0x36;
b_data[18]=0x30;
b_data[19]=0x30;
b_data[20]=0x30;
b_data[21]=0x31;
b_data[22]=0x32;
b_data[23]=0x33;
b_data[24]=0x34;
b_data[25]=0x35;
b_data[26]=0x36;
b_data[27]=0x37;
b_data[28]=0x38;
b_data[29]=0x39;
b_data[30]=0x30;
b_data[31]=0x00;
b_data[32]=0x31; //IMEI
b_data[33]=0x32;
b_data[34]=0x33;
b_data[35]=0x34;
b_data[36]=0x35;
b_data[37]=0x36;
b_data[38]=0x31;
b_data[39]=0x32;
b_data[40]=0x31;
b_data[41]=0x32;
b_data[42]=0x33;
b_data[43]=0x34;
b_data[44]=0x35;
b_data[45]=0x36;
b_data[46]=0x31;
b_data[47]=0x00;
b_data[48]=0x38; //信号强度
b_data[49]=0x00;
b_data[50]=0x00; //用户状态
/*ba_data[51]=0x00; //时间
ba_data[52]=0x00;
ba_data[53]=0x00;
ba_data[54]=0x00;
ba_data[55]=0x00;
ba_data[56]=0x01;
ba_data[57]=0x00;
ba_data[58]=0x03; //日期
ba_data[59]=0x00;
ba_data[60]=0x05;
ba_data[61]=0x00;
ba_data[62]=0x00;
ba_data[63]=0x07;
ba_data[64]=0x00;*/
b_data[51]=0x00; //纬度
b_data[52]=0x33;
b_data[53]=0x33;
b_data[54]=0x33;
b_data[55]=0x33;
b_data[56]=0x33;
b_data[57]=0x33;
b_data[58]=0x2e;
b_data[59]=0x33;
b_data[60]=0x33;
b_data[61]=0x33;
b_data[62]=0x00;
b_data[63]=0x00; //经度
b_data[64]=0x33;
b_data[65]=0x33;
b_data[66]=0x33;
b_data[67]=0x33;
b_data[68]=0x33;
b_data[69]=0x33;
b_data[70]=0x2e;
b_data[71]=0x33;
b_data[72]=0x33;
b_data[73]=0x33;
b_data[74]=0x00;
byte[] temp = new byte[b_data.length + 4];
temp[0] = (byte) 0x60;
temp[1] = (byte) 0x70;
temp[2] = (byte) 0x80;
temp[3] = (byte) 0x90;
System.arraycopy(b_data, 0, temp, 4, b_data.length);
int count = 0;
for(int i=0;i<100000;i++){
count++;
byte[] b = new byte[4];
for (int j = 0; j < 4; j++) {
b[j] = (byte) ((count >> 8 * j) & 0xFF);
temp[12+j]=b[j];
}
outputStream.write(temp);
outputStream.flush();//刷新输出流
}
socket.close();
}catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
服务器端代码如下:
package mars.socket;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class SocketActivity extends Activity {
/** Called when the activity is first created. */
private Button startButton;
private InputStream inputStream=null;
private ServerSocket serverSocket=null;
private Socket socket=null;
private Queue<TempValue> buffer_queue = new LinkedList<TempValue>();;
private ReadWriteLock myLock = new ReentrantReadWriteLock() ;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
startButton = (Button)findViewById(R.id.startListener);
startButton.setOnClickListener(new StartSocketListener());
}
class StartSocketListener implements OnClickListener{
@Override
public void onClick(View v) {
buffer_queue.clear();
ServerThread main=new ServerThread();
main.start();
ManageTcpInfoThread manageThread = new ManageTcpInfoThread();
Thread m = new Thread(manageThread);
m.start();
}
}
class ServerThread extends Thread{
public void run(){
while(true){
try {
serverSocket = new ServerSocket(5500);
socket = serverSocket.accept();
System.out.println("recieve connect socket:"+socket);
ReadTcpInfoThread t=new ReadTcpInfoThread(socket);
Thread r = new Thread(t);
//r.setPriority(MAX_PRIORITY);
r.start();
} catch (IOException e) {
//TODO Auto-generated catch block
e.printStackTrace();
break;
}
try {
serverSocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class ReadTcpInfoThread implements Runnable{
private Socket socket;
private int len;
byte[] buffer = new byte[268];
private int count=0;
public ReadTcpInfoThread(Socket s){
this.socket=s;
}
/* public void finalize()
{
try {
System.out.println("socket close"+socket);
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}*/
public void run(){
try {
inputStream = socket.getInputStream();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
int packetnum=0;
try {
while(true){
int i=inputStream.read(buffer,count,1); //之前采用的方法是一次读12个字节,因为觉得一次读一个字节太慢了,老大说计算机运行的速度每秒十几亿次
//这样每次读一个字节比较保险,并且读不到数据(即i=-1的时候)要跳出来关闭socket。
if(i==-1)
{
System.out.println("socket disconnect"+socket);
socket.close();
break;
}
if(count==0){
if(buffer[count]!=(byte)0x60){
break;
}
}
if(count==1){
if(buffer[count]!=(byte)0x70){
count=0;
break;
}
}
if(count==2){
if(buffer[count]!=(byte)0x80){
count=0;
break;
}
}
if(count==3){
if(buffer[count]!=(byte)0x90){
count=0;
break;
}
}
if(count==11){
len=buffer[count]&0xff;
}
if(count==len+11){
byte[] pack = new byte[8+len];
System.arraycopy(buffer, 4, pack, 0,len+12-4);
TempValue o = new TempValue(pack,len+12-4);
packetnum++;
System.out.println("read a packet packetnum="+packetnum);
myLock.writeLock().lock();
buffer_queue.offer(o);
myLock.writeLock().unlock();
count=0;
continue;
}
count++;
}
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class ManageTcpInfoThread implements Runnable{
byte[] recv_buff;
TempValue p;
int pollnum;
int sleepnum;
int handledpacketnum;
public void run()
{
pollnum=0;
sleepnum=0;
handledpacketnum=0;
while(true){
pollnum++;
myLock.writeLock().lock();
p=buffer_queue.poll();
myLock.writeLock().unlock();
if(p==null||p.rec_len!=p.buf[7]+8)
{
sleepnum++;
try {
Thread.sleep(5);
} catch (InterruptedException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
continue;
}
else
{
handledpacketnum++;
System.out.println("handledpacketnum="+handledpacketnum+"pollnum=" + pollnum+"sleepnum="+sleepnum);
System.out.println(SocketActivity.bytesToHexString(p.buf));
}
}
}
}
public static String bytesToHexString(byte[] src){
StringBuilder stringBuilder = new StringBuilder("");
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length ; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
public class TempValue{
private byte[] buf=new byte[75];
private int rec_len;
public TempValue(byte[] buf,int rec_len){
this.buf=buf;
this.rec_len=rec_len;
}
}
用这个程序发送了十万个包,一个都没有丢。现在正在上班,有时间再补充,大家互相学习一下吧。