SIK05.rst

Sieci Komputerowe

Programowanie socketów. Różne języki *

Java

Przykład, serwer zamieniający komunikat klienta na wielkie litery:

    import java.io.*;
    import java.net.*;

    class tcp
    {
            public static void main(String argv[]) throws Exception
            {
        String clientSentence;
        String capitalizedSentence;
        ServerSocket welcomeSocket = new ServerSocket(6789);

        while(true)
        {
            Socket connectionSocket = welcomeSocket.accept();

            BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));

            DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());

            clientSentence = inFromClient.readLine();

            System.out.println("Received: " + clientSentence);

            capitalizedSentence = clientSentence.toUpperCase() + '\n';

            outToClient.writeBytes(capitalizedSentence);
        }
    }
}

Klient, przykład:

import java.io.*;
import java.net.*;

/**
* Usage:input a string, server will return a value.
**/

class TCPClient {
        public static void main(String argv[]) throws Exception {
                String sentence;
                String modifiedSentence;

                BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));

                Socket clientSocket = new Socket("localhost", 6789);

                DataOutputStream outToServer = new

                DataOutputStream(clientSocket.getOutputStream());

                BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                sentence = inFromUser.readLine();

                outToServer.writeBytes(sentence + '\n');

                modifiedSentence = inFromServer.readLine();

                System.out.println("FROM SERVER: " + modifiedSentence);

                clientSocket.close();
        }
}

Więcej przykładów w Javie:

Zadanie

Zadanie (70 pkt)

Zadaniem Państwa jest napisanie programu grającego w grę kółko i krzyżyk na planszy 5x5, gdzie wygrywającymi układami są proste poziome, pionowe oraz przekątne. Państwa program gra z komputerem a w przypadku remisu na koniec gry, jest on traktowany jak Państwa wygrana.

Serwer za każdym połączeniem rozgrywa po 100 gier i zadaniem Państwa programu jest wygranie co najmniej 75 z nich.

Klient musi komunikować się z serwerem zgodnie z poniższym protokołem. Uwaga! można wykorzystać program netcat do połączenia z serwerem w celu sprawdzenia jak on działa.

Na powitanie Serwer przesyła komunikat:

WELCOME, STATE YOUR NAME

I oczekuje od klienta na wysłanie Swojego loginu w postaci

LOGIN nr_indeksu

Każdy poprawnie odebrany i sparsowany komunikat przez serwer potwierdzany jest komunikatem OK, każdy błędny komunikat oznaczany jest przez serwer poprzez przesłanie do klienta ERROR.

Następnie serwer czeka na spis ruchów użytkownika w postaci:

MOVE nr między 0 a 24

Uwaga! Planszę traktujemy jako zapisaną w postaci - pierwszy wiersz to pola 0..4, drugi wiersz pola 5..9, itd.

W przypadku wysłania ruchu na już zajęte pole otrzymujemy komunikat ERROR.

W odpowiedzi na ruch klienta wysyłany jest albo ruch przeciwnika (który gra całkowicie losowo) postaci:

OPPONENT nr między 0 a 24

Albo komunikat o wygranej

WIN

albo (po komunikacie OPPONENT) komunikat o przegranej

LOST

Po wygranej lub przegranej przesyłany jest także komunikat o rozpoczęciu nowej gry

NEW GAME

Uwaga! Oznacza to że w przypadku przegranej otrzymujemy od serwera trzy komunikaty pod rząd !!

I następnie serwer oczekuje na ruch użytkownika w nowej grze.

Po zakończeniu 100 gier użytkownik powiadamiany jest o wykonaniu zadania - komunikat "SUCCESS" lub porażce - komunikat "FAILED" i serwer kończy komunikację z użytkownikiem (zamyka socket).

W przypadku sukcesu państwa login zapisywany jest do pliku.

SERVER działa pod adresem: 150.254.78.69, na porcie 8787. Uwaga! Serwer jest dostępny tylko z sieci wydziałowej. Implementacja serwera do testów lokalnych dostępna jest tutaj:

uruchomienie:

javac ttt.java
java ttt

Może posłużyć do lokalnych testów, ale ostatecznie w celu uzyskania punktów należy połączyć się z serwerem prowadzącego!

Aby sprawdzić czy udało nam się wykonać zadanie można wejść na stronę i odszukać siebie w pliku

Na Moodle proszę przesłać swój numer indeksu w treści zadania.

Przesyłanie danych binarnych

Serwer odbiera plik jako strumień bitów:

    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.nio.charset.Charset;

    public class FileSerwer {

public static void main(String[] args) throws IOException {
            ServerSocket servsock = new ServerSocket(8888);
            while (true) {
                Socket sock = servsock.accept();

        System.out.println("Accepted connection : " + sock);

                (new Thread() {
                    public void run() {
                        try {
                            InputStream is = sock.getInputStream();
                            byte[] mybytearray = new byte[1000000000];
                            String name = new BufferedReader(new InputStreamReader(is))
                                    .readLine();
                            System.out.println(name);
                            OutputStream os = sock.getOutputStream();
                            String mes = "ok\n";
                            os.write(mes.getBytes(Charset.forName("UTF-8")));
                            FileOutputStream fos = new FileOutputStream(name + ".png");
                            BufferedOutputStream bos = new BufferedOutputStream(fos);

                            // read 4 bytes containing the file size
                            byte[] bSize = new byte[4];
                            int offset = 0;
                            while (offset < bSize.length) {
                                int bRead = is.read(bSize, offset, bSize.length - offset);
                        offset += bRead;
                            }
                            // Convert the 4 bytes to an int
                            int fileSize;
                            fileSize = (int) (bSize[0] & 0xff) << 24
                                    | (int) (bSize[1] & 0xff) << 16
                                    | (int) (bSize[2] & 0xff) << 8
                                    | (int) (bSize[3] & 0xff);

                                    // buffer to read from the socket
                            // 8k buffer is good enough
                    byte[] data = new byte[8 * 1024];

                    int bToRead;
                            while (fileSize > 0) {
                                // make sure not to read more bytes than filesize
                                if (fileSize > data.length) bToRead = data.length;
                                else bToRead = fileSize;
                                int bytesRead = is.read(data, 0, bToRead);
                                if (bytesRead > 0) {
                                    bos.write(data, 0, bytesRead);
                                    fileSize -= bytesRead;
                                }
                            }
                            bos.close();

                            is.close();
                            bos.close();
                            sock.close();
                        } catch (Exception e) {
                            System.out.println(e.getStackTrace());
                        }
                    }
                }).start();
            }
        }
    }

Klient przesyła plik bitowo:

import java.io.*;
import java.net.Socket;

public class FileClient {

    public static void main(String[] argv) throws Exception {

        Socket sock = new Socket("127.0.0.1", 8888);
        sock.setTcpNoDelay(true);

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                  System.out.print("Enter index : ");
                  String input = br.readLine();
                  input += '\n';
                  OutputStream os = sock.getOutputStream();
                  os.write(input.getBytes("UTF-8"));
                  os.flush();
                  String mes = new BufferedReader(new InputStreamReader(sock.getInputStream()))
                  .readLine();

        System.out.println(mes);

        File myFile = new File("saved.png");
        byte[] mybytearray = new byte[(int) myFile.length()];
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(myFile));

        int fSize = (int) myFile.length();
        // Send the file's size
        byte[] bSize = new byte[4];
        bSize[0] = (byte) ((fSize & 0xff000000) >> 24);
        bSize[1] = (byte) ((fSize & 0x00ff0000) >> 16);
        bSize[2] = (byte) ((fSize & 0x0000ff00) >> 8);
        bSize[3] = (byte) (fSize & 0x000000ff);
        // 4 bytes containing the file size
        os.write(bSize, 0, 4);

        int size = bis.read(mybytearray, 0, mybytearray.length);
        sock.getOutputStream().write(mybytearray, 0, size);
        sock.getOutputStream().flush();
        bis.close();
        os.close();
        sock.close();
    }
}

Zadanie (20 pkt)

Wykorzystaj plik FileClient.java do przesłanie do serwera pod adresem 150.254.78.69, na porcie 8888 pliku .png (o wielkości do 1Mb). Serwer oczekuje najpierw na podanie nazwy pliku, którym powinien być twój numer indeksu.

Aby sprawdzić czy udało nam się wykonać zadanie można wejść na stronę i odszukać swój plik

Zadanie (10 pkt)

Korzystając z opisu na stronie:

https://stackoverflow.com/questions/28785437/tcp-sockets-send-buffer-size-efficiency

odpowiedz na pytanie, dlaczego dane w przykładzie dla przesyłania danych binarnych nie są przesyłane za jednym razem tylko dzielone na małe kawałki.

Moodle

Przesyłanie rozwiązań zadań:

*

Wykorzystano materiały z:

https://gist.github.com/roroco/11131088