Java Network - TCP and Socket

The Transmission Control Protocol (TCP) is a core protocol of the Internet protocol suite.

It originated in the initial network implementation in which it complemented the Internet Protocol (IP). Therefore, the entire suite is commonly referred to as TCP/IP.

TCP provides reliable, ordered, and error-checked delivery of a stream of octets between applications running on hosts communicating over an IP network.

Major Internet applications such as the World Wide Web, email, remote administration and file transfer rely on TCP. Applications that do not require reliable data stream service may use the User Datagram Protocol (UDP), which provides a connectionless datagram service that emphasizes reduced latency over reliability.

Socket and ServerSocket

Socket class:

1
2
3
public class Socket
extends Object
implements Closeable

This class implements client sockets (also called just sockets).

A socket is an endpoint for communication between two machines.

The actual work of the socket is performed by an instance of the SocketImpl class. An application, by changing the socket factory that creates the socket implementation, can configure itself to create sockets appropriate to the local firewall.


ServerSocket class:

1
2
3
public class ServerSocket
extends Object
implements Closeable

This class implements server sockets.

A server socket waits for requests to come in over the network. It performs some operation based on that request, and then possibly returns a result to the requester.

The actual work of the server socket is performed by an instance of the SocketImpl class. An application can change the socket factory that creates the socket implementation to configure itself to create sockets appropriate to the local firewall.

Communication between Client and Server

Client Side Procedures

  1. Create TCP client sockets with Socket object. Specify the destination of targeted server when initializing clients
  2. If clients are created successfully, it means the data transportation channel is established. The channel is socket stream, which is constructed underlayer. Since it’s a stream, it indicates that there are both input stream and output stream.

    You can get those two streams from Socket objects by calling getOutputStream() and getInputStream().

  3. Use the stream to transport data
  4. Close resources

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Client End
public class ClientDemo{
/*
Client sends data to Server
*/
public static void main(String args[]) throws UnknownHostException, IOException{
// 1. Create client socket
Socket socket = new Socket("10.128.51.138", 10002);

// 2. Get the output stream from socket
OutputStream out = socket.getOutputStream();

// 3. Use output stream to write data to Server
out.write("TCP demo!".getBytes());

// 4. Close resources
socket.close();
}
}

Server Side Procedures

  1. Create server side socket service by creating ServerSocket object
  2. ServerSocket must provide a port for client to connect to
  3. Get the socket object that tries to connect
  4. Read data from client via the socket object’s stream
  5. Close resources
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Server End
public class ServerDemo {
/**
Get the data from client, and print on console
*/
public static void main(String[] args) throws UnknownHostException, IOException{
// 1. Create server side socket service by creating `ServerSocket` object
// 2. `ServerSocket` must provide a `port` for client to connect to
ServerSocket ss = new ServerSocket(10002);

// 3. Get the socket object that tries to connect
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();

// 4. Read data from client via the socket object's stream
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);

String text = new String(buf, 0, len);
System.out.println(ip + " Server: " + text);

5. Close resources
s.close();
ss.close();
}
}

Interaction between Client and Server - Sending Data back and forth

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Server Side
public class ServerDemo2 {
public static void main(String[] args) throws UnknownHostException, IOException{
ServerSocket serverSocket = new ServerSocket(10002);
Socket socket = serverSocket.accept(); // This is a blocking method

String ip = socket.getInetAddress().getHostAddress();
InputStream in = socket.getInputStream();

byte[] buf = new byte[1024];
int len = in.read(buf);

String text = new String(buf, 0, len);
System.out.println(ip + " " + text);

// Write through ServerSocket's OutputStream to client socket's InputStream
OutputStream out = socket.getOutputStream();
out.write("Received".getBytes());

socket.close();
serverSocket.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Client Side
public class ClientDemo2{
public static void main(String args[]) throws UnknownHostException, IOException{
Socket socket = new Socket("10.128.51.138", 10002);

OutputStream out = socket.getOutputStream();
out.write("TCP demo!".getBytes());

// Use socket's InputStream to read data sent from server
InputStream in = socket.getInputStream();
byte[] buf = new byte[1024];

int len = in.read(buf);

String text = new String(buf, 0, len);
System.out.println(text);

socket.close();
}
}

Text Conversion

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// Server End
public class TransServer{
/*
Analysis:
1. Create ServerSocket
2. Get Socket obejct
3. Get socket's InputStream, and decorate it
4. Get socket's OutputStream, decorate it, and write data through it
5. Close resources
*/
public static void main(String[] args) throws UnknownHostException, IOException{
// 1. Create ServerSocket
ServerSocket ss = new ServerSocket(10004);

// 2. Get Socket obejct
Socket s = ss.accept(); // Blocking!

// Get IP
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"....connected");

// 3. Get socket's InputStream, and decorate it
BufferedReader bIn = new BufferedReader(new InputStreamReader(s.getInputStream()));

// 4. Get socket's OutputStream, decorate it, and write data through it
PrintWriter out = new PrintWriter(s.getOutputStream(),true);

String line = null;
while((line = bIn.readLine()) != null){
System.out.println(line + "...." + line.toUpperCase());
out.println();
}

// 5. Close resources
s.close();
ss.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// Client End
public class TransClient {
/*
Analysis:

Client Side:
1. Need a socket endpoint
2. data source: keyboard input
3. data destination: socket's OutputStream
4. data source from server: socket's InputStream
4. print data on console
6. all data processed is text data
*/
public static void main(String[] args)throws UnknownHostException, IOException{
Socket s = new Socket("10.128.51.138", 10004);

// Get data from keyboard
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

// socket's OutputStream
PrintWriter out = new PrintWriter(s.getOutputStream(), true); // `true` means supporting continue to write

// Read data from server via socket's InputStream
BufferedReader bIn = new BufferedReader(new InputStreamReader(s.getInputStream()));

String line = null;
while((line=br.readLine())!=null){
if("over".equals(line)) {
break;
}

//out.print(line + "\r\n");
//out.flush();
out.println(line);
// Write data to server, println() is PrintWriter's method, is different from System.out.println()

// Read a line of text in upper cases from server
String upperStr = bIn.readLine();
System.out.println(upperStr);
}

s.close();
}
}

Practice

Uploading Files

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class UploadServer {
public static void main(String[] args) throws UnknownHostException, SocketException,IOException{
ServerSocket ss = new ServerSocket(10005);
Socket s = ss.accept();
System.out.println(s.getInetAddress().getHostAddress() + "...connected");

BufferedReader bIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
BufferedWriter bw = new BufferedWriter(new FileWriter("Server.txt"));

String line = null;
while((line = bIn.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}

PrintWriter out = new PrintWriter(s.getOutputStream(),true);
out.println("Successful!");

bw.close();
s.close();
ss.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class UploadClient {
public static void main(String[] args) throws UnknownHostException,SocketException, IOException{
Socket s = new Socket("183.174.66.227", 10005);

BufferedReader br = new BufferedReader(new FileReader("client.txt"));
PrintWriter out = new PrintWriter(s.getOutputStream(),true);

String line = null;
while((line = br.readLine()) != null){
out.println(line);
}

// Tell the server side that client has finished writing
s.shutdownOutput();

BufferedReader bIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
String str = bIn.readLine();
System.out.println(str);

br.close();
bIn.close();
}
}

Uploading Pictures

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class UploadPicServer {
public static void main(String[] args) throws UnknownHostException,SocketException, IOException{
ServerSocket ss = new ServerSocket(10006);
Socket s = ss.accept();

InputStream in = s.getInputStream();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + "....connected");

// Read data and put it in a file
File dir = new File("pic");
if(!dir.exists()) {
dir.mkdirs();
}

File file = new File(dir, ip + ".bmp");
FileOutputStream fos = new FileOutputStream(file);

byte[] buf = new byte[1024];
int len = 0;
while((len=in.read(buf))!=-1){
fos.write(buf,0,len);
}

// Get socket's OutputStream, and send text to client
OutputStream out = s.getOutputStream();
out.write("Successful!".getBytes());

fos.close();
s.close();
ss.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class UploadPicClient {
public static void main(String[] args) throws UnknownHostException,SocketException, IOException{
Socket s = new Socket("183.174.66.227", 10006);
FileInputStream fis = new FileInputStream("0.jpg");
OutputStream out = s.getOutputStream();

byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf))!=-1){
out.write(buf,0,len);
}

// Tell Server that it has finished data transportion, and let server stop reading
s.shutdownOutput();

// Read content from server
InputStream in = s.getInputStream();
byte[] bufIn = new byte[1024];

int lenIn = in.read(buf);
String text = new String(buf, 0, lenIn);
System.out.println(text);

fis.close();
s.close();
}
}

Multi-Threaded Server

Client is the same as the above one.
Only need to change Server side.

1
2
3
4
5
6
7
8
9
10
11
12
public class UploadPicServer {
public static void main(String[] args) throws UnknownHostException,SocketException, IOException{
ServerSocket ss = new ServerSocket(10006);

while(true){
Socket s = ss.accept();
new Thread(new UploadTask(s)).start();
}

ss.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class UploadTask implements Runnable  {
private Socket s;

public UploadTask(Socket s){
this.s = s;
}

@Override
public void run(){
int count = 0;
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + "....connected");

try{
// Read data from client
InputStream in = s.getInputStream();

// Put data into a file
File dir = new File("pic");
if(!dir.exists()) {
dir.mkdirs();
}

File file = new File(dir, ip + ".jpg");

if(file.exists()){
file = new File(dir, ip + " " + (count++) + ".jpg");
}

FileOutputStream fos = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len = 0;
while((len=in.read(buf))!=-1){
fos.write(buf, 0, len);
}

// Get the socket's OutputStream, send response to client
OutputStream out = s.getOutputStream();
out.write("Successful".getBytes());

fos.close();
s.close();
} catch(IOException e) {}
}
}

Common Clients and Server, and Principles behind them

The most common clients - web browser, or custom client
The most common server - web servers, like Apache Tomcat, Ngnix, JBoss, WebSphere

In order to learn the principles of server, let’s implement a mocked server and use existing client - web browser - to see what kind of data client sends to server

Mocked Server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MyTomcatDemo  {
public static void main(String[] args) throws IOException, UnknownHostException, SocketException{
ServerSocket ss = new ServerSocket(9090);
Socket s = ss.accept();
System.out.println(s.getInetAddress().getHostAddress() + "....connected");

InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
String text = new String(buf,0,len);
System.out.println(text);

// Send a message to client
PrintWriter out = new PrintWriter(s.getOutputStream(), true);

out.println("<font size=7>Welcome</font>");

s.close();
ss.close();
}
}

Mocked Client

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MyBrowserDemo  {
public static void main(String[] args) throws IOException, UnknownHostException, SocketException{
Socket s = new Socket("183.174.66.227", 8080);

// Mock web browser, send a HTTP request to Tomcat
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
out.println("GET /1.html HTTP/1.1");
out.println("Accept: */*");
out.println("Host: 183.174.66.227:8080");
out.println("Connection: close");
out.println();
out.println();

InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);

String str = new String(buf, 0, len);
System.out.println(str);

s.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// The message received is:
HTTP/1.1 200 OK // response line, with HTTP version number, status code, and status message
// Response's attribtues- <name>: <value>
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"43-1357224984849"
Last-Modified: Thu, 03 Jan 2013 14:56:24 GMT
Content-Type: text/html
Content-Length: 43
Date: Thu, 03 Jan 2013 16:12:54 GMT
Connection: close
// Empty line
// Response body
<font color = "blue" size=7>welcome</font>