package network.tcpclient;
import java.io.*;
import java.net.*;
import java.util.*;
public class SimpleClient {
public static void main(String[] args) {
if (args.length != 2) {
System.err.println("Usage: java network.tcpclient.SimpleClient host port");
return ;
}
String host = args[0];
int port = Integer.parseInt(args[1]);
new Thread(new TcpClient(host, port)).start();
}
}
class TcpClient implements Runnable {
Socket socket;
String host;
int port;
public TcpClient(String host, int port) {
this.host = host;
this.port = port;
}
public void run() {
try {
socket = new Socket(host, port);
InputStream inFromHost = socket.getInputStream();
OutputStream outToHost = socket.getOutputStream();
InputStream inFromUser = System.in;
OutputStream outToUser = System.out;
byte[] buffer = new byte[1024];
int count = 0;
for (;;) {
count = inFromUser.read(buffer);
if (count <= 0) // EOF indicates a quit
break;
outToHost.write(buffer, 0, count);
count = inFromHost.read(buffer);
outToUser.write(buffer, 0, count);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
package network.tcpserver;
import java.io.*;
import java.util.*;
import java.net.*;
public class EchoServer {
public static void main(String[] args) {
try {
new Thread(new TcpServer(8989)).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class TcpServer implements Runnable {
private ServerSocket serverSocket;
// constructor
public TcpServer(int port) throws IOException {
this.serverSocket = new ServerSocket(port);
}
public void run() {
for (;;) {
try {
Socket socket = serverSocket.accept();
new Thread(new EchoConnectionHandler(socket)).start();
} catch (IOException e) {
e.printStackTrace();
}
} // try
} // run
}
abstract class ConnectionHandler implements Runnable {
private Socket socket;
// constructor
public ConnectionHandler(Socket socket) {
this.socket = socket;
}
public void run() {
handleConversation(socket);
}
// should be overridden by derived classes
abstract public void handleConversation(Socket socket);
}
class EchoConnectionHandler extends ConnectionHandler {
public EchoConnectionHandler(Socket socket) {
super(socket);
}
public void handleConversation(Socket socket) {
try {
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
byte[] buffer = new byte[8192];
int count;
while ((count = in.read(buffer))>=0) {
out.write(buffer, 0, count);
out.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {socket.close();} catch (IOException e) {}
}
}
}
后记:
1. 增加socket.getLocalPort()方法后,打印信息如下:
root@localhost:/home/James/mypro/Network/TcpServer# java network.tcpserver.EchoServer
Server using port: 8989
Connection using port: 8989
root@localhost:/home/James/mypro/Network/TcpClient# java network.tcpclient.SimpleClient localhost 8989
Connection using port: 60822
hello
hello
2. 默认情况下,tcp server监听所有本地的IP地址。如下是客户端的打印:
root@localhost:/home/James/mypro/Network/TcpClient# java network.tcpclient.SimpleClient localhost 8989
Connection using port: 60822
hello
hello
root@localhost:/home/James/mypro/Network/TcpClient# java network.tcpclient.SimpleClient 10.0.0.28 8989
Connection using port: 36185
hello
hello
root@localhost:/home/James/mypro/Network/TcpClient# java network.tcpclient.SimpleClient 10.0.0.29 8989
Connection using port: 37042
hello
hello
3. 一个TCP socket用(src ip, src port, dst ip, dst port)来标识。
如下,增加以下代码后
public void run() {
for (;;) {
try {
Socket socket = serverSocket.accept();
System.out.println("Local host: " + socket.getLocalAddress());
System.out.println("Local port: " + socket.getLocalPort());
System.out.println("Remote host is: " + socket.getInetAddress());
System.out.println("Remote port is: " + socket.getPort());
new Thread(new EchoConnectionHandler(socket)).start();
} catch (IOException e) {
e.printStackTrace();
}
} // try
} // run
运行结果:
root@localhost:/home/James/mypro/Network/TcpServer# java network.tcpserver.EchoServer
Server using port: 8989
Server reuse address: true
Local host: /127.0.0.1
Local port: 8989
Remote host is: /127.0.0.1
Remote port is: 38108
4. accept得到的socket继承listen socket的各种属性,但并不继承local address ,结果如下:
root@localhost:/home/James/mypro/Network/TcpServer# java network.tcpserver.EchoServer
listen socket using address: 0.0.0.0/0.0.0.0:8989
listen socket using port: 8989
listen socket reuse address: true
Local host: /127.0.0.1:8989
Local port: 8989
Remote host is: /127.0.0.1
Remote port is: 33309
增加的代码段是:
public TcpServer(int port) throws IOException {
this.serverSocket = new ServerSocket(port);
System.out.println("listen socket using address: " + serverSocket.getLocalSocketAddress());
System.out.println("listen socket using port: " + serverSocket.getLocalPort());
System.out.println("listen socket reuse address: " + serverSocket.getReuseAddress());
}
0.0.0.0表示此socket只绑定端口,监听本机上所有网络所有IP,具体和哪个ip连,由路由器决定。参考如下博客:
http://hi.baidu.com/cpuramdisk/item/2e46c45f35fc5d3d33e0a90d