引言:网络编程入门
TCP通信程序
TCP能实现两台计算机之间的数据交互,严格区分客户端与服务端
两端通信时步骤:
- 服务端程序,需要事先启动
- 等待客户端的连接
- 客户端主动连接服务器端,连接成功才能通信,服务端不能主动连接客户端
- 这个连接中包含一个对象,这个对象就是IO对象,客户端可以使用IO对象进行通信
- 通信的数据不仅仅是字符,所以IO对象是字节流对象
服务器必须明确两件事情:
多个客户端同时和服务器进行交互,服务器必须明确是哪一个用户
在服务器端有一个方法,叫做accept
客服端获取到请求的客户端对象
多个客户端同时和服务器交互,就需要使用到多个IO流对象
服务器是没有IO流的,服务器可以获取到请求的客服端对象Socket
使用每个客服端Socket
中提供的Socket
流
服务器使用端的字节输入流读取客户端发送的数据,服务器使用客户端的字节输出流给客户端写数据
即:服务器使用客户端的流与客户交流
java中提供了两个类来实现TCP通信:
- 客户端:
java.net.Socket
实现客户端的套接字,套接字是两台机器之间通信的端点,包含了IP地址和端口号的网络单位
- 服务器端:
java.net.ServerSocket
操作步骤
客户端
- 创建一个客户端对象
Socket
,构造方法绑定服务器的IP地址和端口号
- 使用
Socket
对象中的方法getOutputStream()
获取OutputSteam
对象
- 使用
OutputStream
对象中的方法write
给服务器发送数据
- 使用
Socket
对象中的方法getInputStream()
获取InputStream
对象
- 使用
InputStream
对象中的方法read
读取服务器回写的数据
- 释放资源
Socket
服务器端
- 创建服务器
ServerSocket
对象和系统要指定的端口号
- 使用
ServerSocket
对象中的方法accept
,获取到请求的客户端对象Socket
- 使用
Socket
对象中的方法getInputStream()
获取InputSteam
对象
- 使用
InputStream
对象中的方法read
读取客户端发送的数据
- 使用
Socket
对象中的方法getOutputStream()
获取OutputStream
对象
- 使用
OutputStream
对象中的方法write
,给客户端回写数据
- 释放资源
Socket,ServeSocket
Socket
包路径
构造方法
1 2 3 4 5 6 7 8
| public Socker()
public Socket(String host, int port)
|
成员方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public InputStream getInputStream() throws IOException
public OutputStream getOutputStream() throws IOException
public void close() throws IOException
public void setSoTimeOut(int timeOutMilliseconds)
public void connect(SocketAddress address)
public void connect(SocketAddress address,int timeOutInMilliseconds)
public boolean isConnected()
public boolean isClosed()
|
注意:
客户端和服务器交互,必须使用Socket,Socket中提供的网络流不能使用自己创建的流对象
当我们创建客户端对象Socket的时候,就会去请求服务器和服务器经过 三次握手 建立连接通路
这时如果服务器没有启动就会抛出异常
如果服务器已经启动则可以进行交互
半关闭
半关闭(half-close):套接字连接的一端可以终止其输出,同时仍可以接收来自另一端的数据
1 2 3 4 5 6 7 8 9 10 11 12 13
|
public void shutdownOutput()
public void shutdownInput()
public boolean isOutputShutdown()
public boolean isInputShutdown()
|
InetAddress
在主机名和因特网地址之间进行转换
包路径
构造方法
1 2 3 4 5 6 7
| static InetAddress getByName(String host)
static InetAddress[] getAllByName(String host)
|
常用方法
1 2 3 4 5 6 7 8 9 10 11 12 13
| static InetAddress getLocalHost()
byte[] getAddress()
String getHostAddress()
String getHostName()
|
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class InetAddressTest { public static void main(String[] args) throws UnknownHostException { String host = "baidu.com"; InetAddress[] allByName = InetAddress.getAllByName(host); for (InetAddress inetAddress : allByName) { System.out.println(inetAddress);
}
InetAddress localHost = InetAddress.getLocalHost(); byte[] address = localHost.getAddress(); for (byte b : address) { System.out.println(b); } } }
|
ServerSocket
此类实现服务器套接字。服务器套接字等待请求通过网络传入。
它基于该请求执行某些操作,然后可能向请求者返回结果
包路径
构造方法
1 2
| public ServerSocket(int port) throws IOException
|
常用方法
1 2
| public Socket accept()throws IOException
|
实现服务器和客户端的交流
要先运行服务器,再运行客户端
服务器
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
| import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket;
public class TcpServerSocket { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(2020);
Socket accept = serverSocket.accept();
OutputStream outputStream = accept.getOutputStream(); InputStream inputStream = accept.getInputStream();
outputStream.write("你好客户端,这里是服务器".getBytes()); byte[] bytes = new byte[1024]; int len = inputStream.read(bytes); String content = new String(bytes, 0, len, "UTF-8"); System.out.println(content);
accept.close(); serverSocket.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
| import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.Socket;
public class TcpSocket { public static void main(String[] args) throws IOException { Socket socket = new Socket(); socket.connect(new InetSocketAddress("127.0.0.1",2020),10000);
OutputStream outputStream = socket.getOutputStream();
outputStream.write("你好啊服务器,我是客户端".getBytes());
InputStream inputStream = socket.getInputStream(); byte[] bytes = new byte[1024]; int len = inputStream.read(bytes); String content = new String(bytes,0,len,"UTF-8");
System.out.println(content); socket.close(); } }
|
实现多线程
服务器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import java.io.IOException; import java.net.ServerSocket; import java.net.Socket;
public class TcpServerSocketMultithreading { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(2020); while (true){ Socket socket = serverSocket.accept(); Runnable r = new TcpServerSocketMultithreadingImpl(socket); Thread t = new Thread(r); t.start(); } } }
|
实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import java.io.IOException; import java.net.Socket;
public class TcpServerSocketMultithreadingImpl implements Runnable { private Socket socket;
TcpServerSocketMultithreadingImpl(Socket socket) throws IOException { this.socket = socket; } @Override public void run(){ String s = "hello "+ socket.getInetAddress(); try { socket.getOutputStream().write(s.getBytes()); } catch (IOException e) { e.printStackTrace(); }
} }
|