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 (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.
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.