Socket socket=null;



try {
//在客户端建立一个Socket对象,请求建立连接:
socket=new Socket("125.208.3.12",11084);
//输出
System.out.println("连接已建立:"+socket);


OutputStream os=socket.getOutputStream();
InputStream in=socket.getInputStream();                        //发送登录
os.write(login.getBytes());
os.flush();
Thread.sleep(3000);

//发送信息01
os.write(sendmes.getBytes());
os.flush();
Thread.sleep(3000);

                        //发送信息02
os.write(sendmes1.getBytes());
os.flush();

int c;
while((c=in.read())!=-1)
{
System.out.print((char)c);
}


} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
调用这些代码可以实现给手机发送短信的功能,我现在是客户端,我给服务端发送数据后,手机号可以接收到我发送的信息。在我发送了第一条信息后,手机可以收到短息,但是执行第二条发送信息的时候,手机就是收不到信息了!客户端也只能收到登录和第一条短信发送的返回信息,请问下这个是什么原因呢?
另外他这个还有一个心跳报文,我要是连续发送俩次心跳报文的时候就都可以收到返回的信息!会不会是他们服务端的问题呢?还是我代码的问题呢?socket通信

解决方案 »

  1.   

    要看服务端的ServerSocket是只有一次accept还是多次的了。
    (嘿,LZ好纠结呀~)
      

  2.   

    真心纠结呀,第一次搞这东西。都折腾快半个月了!
    服务端在人家那边,并且别人客户端有做成功的,感觉还是我代码的问题,但是现在不知道是哪的问题了!
    我现在只是在一个main方法里测试的!不知道是不是这得问题呢?但是我看他的文档里说的是登陆成功以后可以发送任何形式的报文给服务端,但是我连续发送俩条短信报文以后还是只能收到第一条!第二条这老是不行
      

  3.   

    socket.close(),然后再次执行试试。
      

  4.   

    他有个心跳报文,我连续发送俩条就没问题,只要一发送在哪儿关闭呢?fianlly?
      

  5.   

    放finally或while后面都可以的。试试呗~
      

  6.   

    中文还没遇见呢,现在正在想接受返回值的问题!在缓冲区的时候会粘包,我要怎么样才能一条条的接收数据,再放到集合里呢?

    可不可以做个标记,比如以某个特殊字符或节点开头、结尾,表示一个包,这样来区分呢?
    我现在的代码是这样的:先读取到他的长度,再根据长度把该条报文剩余的数据读取出来,最后再把这条报文拼接起来!
    因为我要循环读取,就是现在这些代码要放到一个while循环里,不断的读取服务端返回的数据
    每当读到一条完整的报文是就存储到队列里!(要让他只要有数据就一直读取呢,存储呢!)
    正在思考要怎么把读到的这些报文存起来呢!还有while的条件不知道改怎么填,是写true呢,还是别的呢!总感觉有些东西不太确定!怕写了半天出错了!
    下午看了会多线程,写了一个简单的多线程循环向队列存值,取值的示例!
    先帮我参考下下面这样写可以吗?//读取块标识
    byte[] bblockMark=new byte[3];
    in.read(bblockMark);
    String blockMark=new String(bblockMark);

    //读取版本识别码
    byte[] bverID=new byte[1];
    in.read(bverID);
    String verid=new String(bverID);

    //读取报文长度
    byte[] bmesgLen=new byte[6];
    in.read(bmesgLen);
    String mlen=new String(bmesgLen);
    int len=Integer.parseInt(mlen);

    //读取本条报文剩余的数据
    byte[]result=new byte[len-10];
    in.read(result);
    String th=new String(result);

    //返回整条的完整报文
    String message=blockMark+verid+mlen+th;
    System.out.println(message);
      

  7.   

    看到粘包描述,有这么一段话:"有可能后续发送的数据和之前发送的数据同时存在缓冲区中随后一起发送"。不清楚你们的系统能不能保证先后顺序。如果能保证FIFO,你的方式是可以的。如果会有先后顺序不一情况的话,按长度就很有风险了。你的代码“读取报文长度”,mlen这样处理的话,只能是个位数的长度了对吧?建议长度直接转换为byte存储,解析的时候也直接读取即可:int len=bmesgLen;这样长度最大可达0~127。
     //读取本条报文剩余的数据
                    byte[]result=new byte[len-10];
    这一步为啥要减10,不太理解。其它没啥建议了。
      

  8.   

    按我目前的理解是:他给我返回信息是异步的,就是我连续向服务端发送多条数据,然后再一起接收这多条数据的返回信息,你说的先后顺序是说接收这得顺序与发送的信息的顺序是否一致吗?
    目前我是这样想得:先把这些信息存储起来,然后再一条条的判断哪个成功,哪个失败!这样对于我接收到的先后顺序应该就不用考虑了吧!因为我是按长度接收的,所以每条报文都应该是完整的吧?我接收到哪条的返回信息就判断哪条的返回信息!
    但是这样的话,我的心跳报文发送以后要接收得话要怎么弄呢?难道在队列里取值判断以后如果是心跳报文的应答报文再返还给这?
    因为他的长度占的是6个字节的位置,我使用byte数组读到后,先把这个字节数组转为字符串是为了取得他的长度,假如我的长度为000150的话,我转成String后显示的是000150,我再转下int就是150了,即这条报文的长度。len-10,len代表的是这条报文的长度,-10是因为我在缓冲区已经读取了10个字节流了,所以我只能读取这条报文在缓冲区的剩余的150-10个字节流了!
      

  9.   

    按我目前的理解是:他给我返回信息是异步的,就是我连续向服务端发送多条数据,然后再一起接收这多条数据的返回信息,你说的先后顺序是说接收这得顺序与发送的信息的顺序是否一致吗?
    目前我是这样想得:先把这些信息存储起来,然后再一条条的判断哪个成功,哪个失败!这样对于我接收到的先后顺序应该就不用考虑了吧!因为我是按长度接收的,所以每条报文都应该是完整的吧?我接收到哪条的返回信息就判断哪条的返回信息!
    但是这样的话,我的心跳报文发送以后要接收得话要怎么弄呢?难道在队列里取值判断以后如果是心跳报文的应答报文再返还给这?
    因为他的长度占的是6个字节的位置,我使用byte数组读到后,先把这个字节数组转为字符串是为了取得他的长度,假如我的长度为000150的话,我转成String后显示的是000150,我再转下int就是150了,即这条报文的长度。len-10,len代表的是这条报文的长度,-10是因为我在缓冲区已经读取了10个字节流了,所以我只能读取这条报文在缓冲区的剩余的150-10个字节流了!

    嗯,你的这种读取思路很好啊,赞一个~
    建议blockMark、bverID还是要判断下,合法值才继续往下读。
    其它的,没实际用过,也不好建议啦~
      

  10.   


    public class readThread implements Runnable{

    //线程
    public void run()
    {
    readwork();
    }


    //接受完整报文的队列
    private final  LinkedList ReciveMessage=new LinkedList();

    //解析存入的集合
    List<MessageEntity> list=new ArrayList<MessageEntity>();

    //向队列添值
    public void addReciveMessage(String message)
    {
    synchronized(this)
    {
    ReciveMessage.add(message);
    this.notifyAll();
    }

    }

    //获取队列的值
    //获取队列的第一个值
    public synchronized Object getReciveMessage() throws InterruptedException
    {
    while(ReciveMessage.isEmpty())
    {
    wait();
    }
    return ReciveMessage.removeFirst();
    }


    //读取服务端返回的数据并调用解析的方法将解析的数据存储到集合中()
    public synchronized void readwork()
    {
    while(true)
    {
    //上面的代码
    //向队列添加数据(读取到的完整报文)
        addReciveMessage(message);
        //调用解析报文的方法添加到list集合
        jiexi(getReciveMessage());
    }
    }

    //解析的fangfa
        public void jiexi(String message)
        {
         //实体类
         MessageEntity me=new MessageEntity();
        
         //将解析后的数据存入到list集合
         list.add(me);
        }os.write(login.getBytes());
    os.flush();

    os.write(echo.getBytes());
    os.flush();

    os.write(echo.getBytes());
    os.flush();

    os.write(echo.getBytes());
    os.flush();

    readThread  r=new readThread(in);
    Thread t=new Thread(r);
    t.start();

                            //加入这句,可以再list集合里读到数据
                            Thread.sleep(3000); for (int i = 0; i < r.list.size(); i++) {
    System.out.println("返回状态:"+r.list.get(i).getBrespCode());
    }你好,帮我看下这个问题!上面的代码是我写了一个readThread的线程,步骤是:读取完整的报文>>将完整的报文先存到队列中>>从队列中获取一条报文解析并将解析到的数据存到list集合中!
    现在的问题是,我在main方法里测试的时候(下边的代码)我直接输出read线程的list集合是获取不到数据的!我在线程开始时加入了一句sleep就可以读到线程的数据了!我上面写的几个方法,(向队列加值,从队列取值,读取队列的值,解析队列的值)都加了一个synchronized,这是我参考的别的代码加上的,是让线程同步的!现在有个疑问,我现在就仅仅使用了一个线程,我现在加不加synchronized都可以是吧,还有现在在向队列添值和取值的时候是不是写的那个wait()和this.notifyAll();是不是没用呢!但是基于刚才那个在main方法里加入sleep这句才可以取到解析后返回的值!现在我想这样弄就是:再开一个线程,要让他能够及时的输出list集合里的值,而不用在main方法里sleep几秒。也就是说我要让这个线程可以在有数据的时候,就this.notifyAll()唤醒他,没有数据的时候就wait(),等待他输入数据后就在此this.notifyAll()唤醒他,要怎么写呢?给我说下思路也可以!下午我自己写了一个线程,可是还是没写对!顺便先帮我参考下上面的代码,我要怎么改下。我感觉现在这得代码有问题,但不知道哪的问题,怎么改..谢谢了!
      

  11.   

    对于第一个类,稍微改了下,LZ可以参考下(核心思想就是在操作list的地方,将list锁住,其它地方无需加锁,加了也没用,因为这个多线程的时候,会实例化多次,非静态方法的锁就没有意义了。另外就是把list改成静态的了,这样多个线程可以读写同一份list了)public class readThread implements Runnable{
        
        //线程
        public void run()
        {
            readwork();
        }
         
         
        //接受完整报文的队列
        public final static  LinkedList ReciveMessage=new LinkedList();
         
        //解析存入的集合
        List<MessageEntity> list=new ArrayList<MessageEntity>();
         
        //向队列添值
        public void addReciveMessage(String message)
        {
            synchronized(ReciveMessage)
            {
                ReciveMessage.add(message);
                this.notifyAll();
            }
             
        }
         
        //获取队列的值
        //获取队列的第一个值
        public Object getReciveMessage() throws InterruptedException
        {
            while(ReciveMessage.isEmpty())
            {
                wait();
            }
            synchronized (ReciveMessage)
            {
                return ReciveMessage.removeFirst();
            }
        }
         
         
        //读取服务端返回的数据并调用解析的方法将解析的数据存储到集合中()
        public void readwork()
        {
            while(true)
            {
                //上面的代码
                //向队列添加数据(读取到的完整报文)
                addReciveMessage(message);
                //调用解析报文的方法添加到list集合
                jiexi(getReciveMessage());
            }
        }
         
        //解析的fangfa
        public void jiexi(String message)
        {
            //实体类
            MessageEntity me=new MessageEntity();
             
            //将解析后的数据存入到list集合
            list.add(me);
        }
    }另外一个需求,可以考虑使用Observer接口和Observable类,实现观察者:当线程对list进行add操作时,触发下观察者。LZ可以搜下观察者实现案例,不难的。
      

  12.   

    另外,wait方法,没怎么用过,如果是测试方法,可以使用,项目里还是慎用吧。(main方法里的sleep的原因是,你的线程start之后,是异步的了,需要一段时间才能执行完,所以要sleep才有结果)
      

  13.   

    看你的意思是不是说队列就不用锁了呢?list锁住就行?还有我看你说的把list改成静态的,是不是上面写错了呢,怎么是把队列改成静态的了!假如我在这儿写完以后,在另一个线程里要调用这个线程是不是这些方法就得加锁了呢?就是另一个线程要调用这个线程,这个线程要调用这些方法!还有我上次看到一个单态模式(应该是一个类只能实例化一次了吧?),因为多线程的情况下会实例化多次,这样会有什么隐患吗?使用单态模式是为了避免什么呢?还有,我最后是要写一个Servlet接口,然后在接口里面传值,将信息发送出去的,是不是现在在main方法里测试不合适呢!或者是我还没写后面的发送线程,这个传值也要使用到线程和队列吧?我要在保持socket连接的时候通过队列来向线程里面传值,使他可以在socket连接的时候,从队列中获取值然后发送!就是队列有值就让线程去发送,没值就等待?
      

  14.   

    我要是想避免使用sleep的话,要怎么弄呢?
      

  15.   

    看你的意思是不是说队列就不用锁了呢?list锁住就行?还有我看你说的把list改成静态的,是不是上面写错了呢,怎么是把队列改成静态的了!
    --你不是想公用一个队列来处理的么?当然要操作同一个list了。如果我理解错了的话,那你把static去掉好了。假如我在这儿写完以后,在另一个线程里要调用这个线程是不是这些方法就得加锁了呢?就是另一个线程要调用这个线程,这个线程要调用这些方法!
    --方法加不加锁,要看情况。比如你的这个类,如果new了多个线程对象,就算方法(非静态方法)加锁了,也只是锁住new的对象那块的方法。还有我上次看到一个单态模式(应该是一个类只能实例化一次了吧?),因为多线程的情况下会实例化多次,这样会有什么隐患吗?使用单态模式是为了避免什么呢?
    --单例一般是某个接口功能,或者工具类,对外呈现的时候,要保持单一性,避免互斥操作以及减少内存消耗。使用多线程,十有八九是为了互斥操作,应该会new多次的,不要使用单例。还有,我最后是要写一个Servlet接口,然后在接口里面传值,将信息发送出去的,是不是现在在main方法里测试不合适呢!或者是我还没写后面的发送线程,这个传值也要使用到线程和队列吧?我要在保持socket连接的时候通过队列来向线程里面传值,使他可以在socket连接的时候,从队列中获取值然后发送!就是队列有值就让线程去发送,没值就等待?
    --main里测试可以的,servlet实现的时候,也可以使用sleep的,虽然不是很好。不过话说回来,一个servlet请求,就没必要使用多线程来测试了,直接串行操作,没问题的。
    --sock本身可以多线程,但是针对每一个socket,似乎发一条消息,就会等待了的,不需要人为操作去等的吧?
      

  16.   

    我现在专门写了一个类,用来存放队列,当我在while循环读取到数据后,先将它存到第一个队列里!然后再开一个线程,从该队列中先获取一条报文然后解析,将解析后的报文根据报文号的不同分别放到:登录返回队列或心跳返回队列或发送短信返回的队列里!目前感觉还可以!
    在while循环里读取到数据的时候,我是使用了线程里的wait()和this.notifyAll(),来控制线程的!当有数据的时候就唤醒线程,没数据的时候就等待了!public class test3 {

    //读取服务端返回的报文存放的集合
    public static LinkedList reportLink=new LinkedList();

    //解析后的报文存放在此处
    public static LinkedList<MessageEntity> resultList=new LinkedList<MessageEntity>();

    //解析后将登录返回的报文存到此队列
    public static LinkedList<MessageEntity> loginreportLink=new LinkedList<MessageEntity>();

    //将解析后的心跳报文存到此队列
    public static LinkedList<MessageEntity> echoreportLink=new LinkedList<MessageEntity>();



    }这个是俩个方法分别是从队列获取值和向队列添值写的方法,等待和唤醒线程就是通过这执行的!public synchronized void addMessage(String message)
    {
    reportLink.add(message);

    this.notifyAll();
    }

    public synchronized String getMessage() throws InterruptedException
    {
    while(reportLink.isEmpty())
    {
    wait();
    }
    // System.out.println("输出"+reportLink.removeFirst());
    return (String) reportLink.removeFirst();

    }另外请教一个问题:
    这个代码是我使用死循环读取服务端给我返回数据方法,这个方法是放在一个线程里的执行的!
    现在想问的是,上次我请教一个人,他说让我把线程休眠一下,说是为了防止死循环造成CPU使用过高,导致电脑瘫痪!我得理解是既然我读取服务端的数据是一个堵塞的方法,这个休眠写不写还有意思吗?while(true)
    {
    //读取数据
    byte[]b=new byte[150];

    //存入集合
    linkedlist.add(new String (b));


    //此处要让这个循环休眠一下,不知道这样写的用意是什么?
    Thread.sleep(2);
    }
      

  17.   

    你的那个while(true)会无间断的读取数据,加入list,感觉这里使用wait也是可以的。如果wait和sleep都没有,这样操作下去可能会有问题。另外,你的这段代码应该不是真实使用的代码吧?
    还有,建议byte[] b这个声明放到循环体外面,这样就不会每次执行都重新声明一个引用b了。
      

  18.   

    while(true)里的代码就是15楼我粘的那些代码,只不过最后把他放入到一个队列里了!我就是这样使用的,不知道有什么隐患吗?将byte[]b这个声明放到循环外面,就不会每次执行都重新声明一个引用b了。这样是为了避免什么呢?
      

  19.   

    while(true)里的代码就是15楼我粘的那些代码,只不过最后把他放入到一个队列里了!我就是这样使用的,不知道有什么隐患吗?将byte[]b这个声明放到循环外面,就不会每次执行都重新声明一个引用b了。这样是为了避免什么呢?
    看不出来有啥问题。
    编码规范中,要求将对象的声明放到循环体外。否则每次循环都要重新声明一个引用,占用栈空间。