一、概述
TCP通信能实现两台计算机之间的数据交互,通信的两端,要严格区分为客户端(Client)与服务端(Server)。
二、Socket类
TCP通信的客户端:向服务器发送连接请求,给服务器发送数据,读取服务器回写的数据
Socket 类:此类实现客户端套接字(也可以就叫“套接字”)。- 套接字是两台机器间通信的端点。
- 套接字:包含了 IP 地址和端口号的网络单位 。
2.1 构造方法
-
public Socket(String host, int port) :创建套接字对象并将其连接到指定主机上的指定端口号。如果指定的host是null ,则相当于指定地址为回送地址。
小贴士:回送地址(127.x.x.x) 是本机回送地址(Loopback Address),主要用于网络软件测试以及本地机进程间通信,无论什么程序,一旦使用回送地址发送数据,立即返回,不进行任何网络传输。
构造举例,代码如下: Socket client = new Socket("127.0.0.1", 8888);
2.2 成员方法
public InputStream getInputStream() : 返回此套接字的输入流。
- 如果此
Scoket 具有相关联的通道,则生成的 InputStream 的所有操作也关联该通道。 - 关闭生成的
InputStream 也将关闭相关的 Socket 。 public OutputStream getOutputStream() : 返回此套接字的输出流。
- 如果此
Scoket 具有相关联的通道,则生成的 OutputStream 的所有操作也关联该通道。 - 关闭生成的
OutputStream 也将关闭相关的Socket。 public void close() :关闭此套接字。
- 一旦一个
socket 被关闭,它不可再使用。 - 关闭此
socket 也将关闭相关的 InputStream 和 OutputStream 。 public void shutdownOutput() : 禁用此套接字的输出流。
2.3 实现步骤
- 创建一个客户端对象
Socket ,构造方法绑定服务器的IP地址和端口号 - 使用
Socket 对象中的方法 getOutputStream() 获取网络字节输出流 OutputStream 对象 - 使用网络字节输出流
OutputStream 对象中的方法 write ,给服务器发送数据 - 使用
Socket 对象中的方法 getInputStream() 获取网络字节输入流 InputStream 对象 - 使用网络字节输入流
InputStream 对象中的方法 read ,读取服务器回写的数据 - 释放资源 (Socket)
注意:
- 客户端和服务器端进行交互,必须使用
Socket 中提供的网络流,不能使用自己创建的流对象 - 当我们创建客户端对象
Socket 的时候,就会去请求服务器,和服务器经过3次握手建立连接通路
- 这时如果服务器没有启动,那么就会抛出异常
ConnectException: Connection refused: connect - 如果服务器已经启动,那么就可以进行交互了
三、ServerSocket类
TCP通信的服务器端:接收客户端的请求,读取客户端发送的数据,给客户端回写数据
ServerSocket 类:这个类实现了服务器套接字,该对象等待通过网络的请求。
3.1 构造方法
3.2 成员方法
服务器端必须明确一件事情,必须的知道是哪个客户端请求的服务器,所以可以使用 accept 方法获取到请求的客户端对象 Socket
public Socket accept() :侦听并接受连接,返回一个新的Socket对象,用于和客户端实现通信。该方法会一直阻塞直到建立连接。
3.3 实现步骤
- 创建服务器
ServerSocket 对象和系统要指定的端口号 - 使用
ServerSocket 对象中的方法 accept ,获取到请求的客户端对象 Socket - 使用
Socket 对象中的方法 getInputStream() 获取网络字节输入流 InputStream 对象 - 使用网络字节输入流
InputStream 对象中的方法 read ,读取客户端发送的数据 - 使用
Socket 对象中的方法 getOutputStream() 获取网络字节输出流 OutputStream 对象 - 使用网络字节输出流
OutputStream 对象中的方法 write ,给客户端回写数据 - 释放资源(Socket,ServerSocket)
四、简单的TCP网络程序
4.1 TCP通信分析图解
- 【服务端】启动,创建
ServerSocket 对象,等待连接。 - 【客户端】启动,创建
Socket 对象,请求连接。 - 【服务端】接收连接,调用
accept 方法,并返回一个 Socket 对象。 - 【客户端】
Socket 对象,获取 OutputStream ,向服务端写出数据。 - 【服务端】
Scoket 对象,获取 InputStream ,读取客户端发送的数据。
到此,客户端向服务端发送数据成功。
自此,服务端向客户端回写数据。
- 【服务端】
Socket 对象,获取 OutputStream ,向客户端回写数据。 - 【客户端】
Scoket 对象,获取 InputStream ,解析回写数据。 - 【客户端】释放资源,断开连接。
4.2 TCP网络程序
服务端实现:
public class ServerTCP {
public static void main(String[] args) throws IOException {
System.out.println("服务端启动 , 等待连接 .... ");
ServerSocket ss = new ServerSocket(8888);
Socket server = ss.accept();
InputStream is = server.getInputStream();
byte[] b = new byte[1024];
int len = is.read(b);
String msg = new String(b, 0, len);
System.out.println(msg);
OutputStream out = server.getOutputStream();
out.write("我很好,谢谢你".getBytes());
out.close();
is.close();
server.close();
}
}
客户端实现:
public class ClientTCP {
public static void main(String[] args) throws Exception {
System.out.println("客户端 发送数据");
Socket client = new Socket("localhost", 8888);
OutputStream os = client.getOutputStream();
os.write("你好么? tcp ,我来了".getBytes());
InputStream in = client.getInputStream();
byte[] b = new byte[100];
int len = in.read(b);
System.out.println(new String(b, 0, len));
in.close();
os.close();
client.close();
}
}
结果如图
五、练习–上传文件
5.1 C/S基础版本–单线程
-
服务器端实现 读取客户端上传的文件,保存到服务器的硬盘,给客户端回写"上传成功" public class TCPServer {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8888);
Socket socket = server.accept();
InputStream is = socket.getInputStream();
File file = new File("D:\\upload");
if(!file.exists()){
file.mkdirs();
}
FileOutputStream fos = new FileOutputStream(file+"\\1.jpg");
System.out.println("11111111111111111111");
int len =0;
byte[] bytes = new byte[1024];
while((len = is.read(bytes))!=-1){
fos.write(bytes,0,len);
}
System.out.println("22222222222222222222222 while死循环打印不到");
socket.getOutputStream().write("上传成功".getBytes());
fos.close();
socket.close();
server.close();
}
}
-
客户端实现 读取本地文件,上传到服务器,读取服务器回写的数据 public class TCPClient {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("D:\\1.jpg");
Socket socket = new Socket("127.0.0.1",8888);
OutputStream os = socket.getOutputStream();
int len = 0;
byte[] bytes = new byte[1024];
while((len = fis.read(bytes))!=-1){
os.write(bytes,0,len);
}
socket.shutdownOutput();
InputStream is = socket.getInputStream();
System.out.println("333333333333333333333");
while((len = is.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}
System.out.println("444444444444444444 while死循环打印不到");
fis.close();
socket.close();
}
}
5.2 C/S 升级版本–多线程
客户端实现不变,服务器实现如下:
public class TCPServer {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8888);
while(true){
Socket socket = server.accept();
new Thread(new Runnable() {
@Override
public void run() {
try {
InputStream is = socket.getInputStream();
File file = new File("d:\\upload");
if(!file.exists()){
file.mkdirs();
}
String fileName = System.currentTimeMillis()+new Random().nextInt(999999)+".jpg";
FileOutputStream fos = new FileOutputStream(file+"\\"+fileName);
int len =0;
byte[] bytes = new byte[1024];
while((len = is.read(bytes))!=-1){
fos.write(bytes,0,len);
}
socket.getOutputStream().write("上传成功".getBytes());
fos.close();
socket.close();
}catch (IOException e){
System.out.println(e);
}
}
}).start();
}
}
}
5.3 B/S 升级版本
客户端浏览器,web代码就不粘贴了,详情已放到下载区–java进阶代码11-Net 服务器实现
public class TCPServer {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8080);
Socket socket = server.accept();
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = br.readLine();
String[] arr = line.split(" ");
String htmlpath = arr[1].substring(1);
FileInputStream fis = new FileInputStream(htmlpath);
OutputStream os = socket.getOutputStream();
os.write("HTTP/1.1 200 OK\r\n".getBytes());
os.write("Content-Type:text/html\r\n".getBytes());
os.write("\r\n".getBytes());
int len = 0;
byte[] bytes = new byte[1024];
while((len = fis.read(bytes))!=-1){
os.write(bytes,0,len);
}
fis.close();
socket.close();
server.close();
}
}
图解 但是运行客户端浏览器发现图片不显示,经下面修改后,图片显示正常
public class TCPServerThread {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8080);
while(true){
Socket socket = server.accept();
new Thread(new Runnable() {
@Override
public void run() {
try {
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = br.readLine();
System.out.println(line);
String[] arr = line.split(" ");
String htmlpath = arr[1].substring(1);
FileInputStream fis = new FileInputStream(htmlpath);
OutputStream os = socket.getOutputStream();
os.write("HTTP/1.1 200 OK\r\n".getBytes());
os.write("Content-Type:text/html\r\n".getBytes());
os.write("\r\n".getBytes());
int len = 0;
byte[] bytes = new byte[1024];
while((len = fis.read(bytes))!=-1){
os.write(bytes,0,len);
}
fis.close();
socket.close();
}catch (IOException e){
e.printStackTrace();
}
}
}).start();
}
}
}
|