Socket网络编程

最近写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;
       }
   }
    
用这个程序发送了十万个包,一个都没有丢。现在正在上班,有时间再补充,大家互相学习一下吧。

原文地址:https://www.cnblogs.com/leihupqrst/p/3110105.html