Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java ME (J2ME) > Socket соединение через InputStream, OutputStream?


Автор: Kalisnik 1.4.2012, 19:55
На сервере открываю Серверный сокет, на клиенте Клиентский. Однако, клиент отправляет через OutputStream байты только тогда, когда я закрываю клиетнтский сокет (почему так?). А мне нужно что бы клиент постоянно был соединен с сервером и получал от сервера данные без запроса. Как такое реализовать? Наверно лучше реализовать это по протоколу TCP.

Автор: oxigen 2.4.2012, 16:36
Набросал что-то страшненькое, но вроде работает.
Клиент отправляет на сервер введеную строку, добавляя к ней \n в качестве флага конца пакета.
Сервер печатает ее в консоль, дописывает в конец ::SERVER ANSWER и отправляет клиенту. Тот ее показывает.

На симуляторе вполне работает. Сервер нужно запускать первым.

Сервер
Код

public class TestClass {
   
    PrintWriter out;
    BufferedReader in;

    public static void main(String[] args) {
        
        try{
            TestClass tc = new TestClass();
            tc.initSocket();
            tc.listenForSocket();
        } catch (Exception e) {
        }
     
    }

    private void initSocket() {
        ServerSocket ss;
        try {
            ss = new ServerSocket(1234);
            Socket connection = ss.accept();
            out = new PrintWriter(connection.getOutputStream(), true); 
            in = new BufferedReader(new InputStreamReader(connection.getInputStream())); 
        } catch (IOException e) {
        }
    }
    
    private void listenForSocket() {
            try {
                StringBuffer sb = new StringBuffer();
                int ch = 0;
                while ((ch = in.read()) != -1){ 
                    if(ch == '\n') {
                        System.out.println(sb);
                        sendMessage(sb.append("::SERVER ANSWER").toString());
                        sb = new StringBuffer();
                    } else {
                        sb.append((char)ch); 
                    }
                }
            } catch (Exception e) {
            } 
        
    }
        
    private void sendMessage(String msg) {
        try{
            out.write(msg);
            out.flush();
        }
        catch(Exception ioException){
           
        }
    }
    
    
}


Клиент

Код

public class SocketTest extends MIDlet implements CommandListener {

    private Command send = new Command("Send", Command.OK, 0);
        
        private TextField text;
        private SocketConnection sc;
        private DataOutputStream os;
        private DataInputStream is;
        private Form form;

        public SocketTest() {
        }
        
        public void pauseApp() {
        }
        
        public void destroyApp(boolean unconditional) {
            notifyDestroyed();
        }

        public void startApp() {
            initSocket();
            form = new Form("SocketTest");
            text = new TextField("", "", 100, TextField.ANY);
            form.append(text);
            form.setCommandListener(this);
            form.addCommand(send);
            Display.getDisplay(this).setCurrent(form);
        }

        public void commandAction(Command c, Displayable d) {
            if(c == send){
               try {
                String textForSend = text.getString() + "\n";
                os.write(textForSend.getBytes());
                text.setString("");
            } catch (IOException e) {
            }
            }
        }
    
        private void initSocket() {
            try {
                sc = (SocketConnection)Connector.open("socket://127.0.0.1:1234");
                os = sc.openDataOutputStream();
                is = sc.openDataInputStream();
                startReadingThread();
            } catch (IOException e) {
                System.out.println(e);
            }
        }


        private void startReadingThread() {
            Runnable readingThread = new Runnable() {
                public void run() {
                    while (true) {
                        try {
                            int size = is.available();
                            if (size > 0) {
                                byte[] b = new byte[size];
                                is.readFully(b);
                                String fromserver = new String(b);
                                Alert alert = new Alert(fromserver);
                                Display.getDisplay(SocketTest.this).setCurrent(alert, form);
                            }
                            
                            Thread.sleep(100);
                            
                        } catch (Exception e) {
                        }
                        
                    }
                }
            };
            
            (new Thread(readingThread)).start();
            
        }

}



Автор: Kalisnik 5.4.2012, 14:57
oxigen, спасибо. Многое прояснилось. Однако смущает метод startReadingThread() - такого написания я еще не видел:

Код

Runnable readingThread = new Runnable() {}; // Почему фигурные скобки? И точка с запятой в конце?


Runnable - интерфейс. С помощью ключевого слова new ссылке readingThread с типом Runnable выделяется память. Т.е. создается объект Runnable из интерфеса? Но в интерфейсе Runnable даже конструктора нету, ведь он - интерфейс. Или new Runnable() {}; - это и есть созданный вручную конструктор? А то что заключено в фигурные скобки, его реализация? Почему без точки с запятой после закрывающей кавычки редактор ругается на синтаксическую ошибку?

Автор: oxigen 5.4.2012, 17:41
Погуглите. Это анонимный класс.

Иногда нужен небольшой класс, который будет использоваться только в одном месте.
Можно конечно написать как обычно
Код

class ReadingClass implements Runnable {
    public void run() {}
}
.....
Runnable readingThread = new ReadingClass();

А можно написать то же самое через анонимный класс
Код

Runnable readingThread = new Runnable() {
    public void run() {}
};

Точка с запятой как видите и там и там в конце - оператор присваивания так выглядит. куда_присвоить = что присвоить ;

Анонимный класс удобен тем, что сразу на месте видна его реализация. Runnable часто так используют. Потоков много и разных нужно создавать, метод run() обычно небольшой и выносить их все в отдельные классы нет смысла. 

Из неудобств анонимных классов - можно использовать только в одном месте, нельзя ему конструктор сделать.

Автор: Kalisnik 5.4.2012, 18:42
oxigen, спасибо еще раз.

Автор: zloyMolo4nik 5.10.2012, 00:23
Доброго времени суток. Сделал тестовую программу "Чат" между компом и телефоном. Сервер на сокетах, написан на делфи. Клиент установлен на телефон, написан на j2me. Отправку сообщений с клиента реализовал так  
Код



 public void Send ()
     {
         try
         {
             try
             {
                 outputStream = socketConnection.openOutputStream();
                 byte[] data = (textField.getString()).getBytes();
                 outputStream.write(data);
                 outputStream.flush();                 
             }finally{outputStream.close();}
         }catch(IOException ioe){}
     }  

Также в клиенте есть прослушка открытого сокета. она вынесена в отдельный поток. Проблема в том, что когда я с телефона отправил сообщение на комп,  то отправить сообщение еще раз не получается, приходится переконечивать клиент. Прием сообщений работает идеально. Все сообщения приходят. Подскажите плз что делать, где может быть ошибка. Или может отправку сообщений вынести тоже в отдельный поток?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)