TCP网络编程
这里我们通过一个例子来了解什么是TCP网络编程:
eg: 问题: —> 从客户端发送文件到服务端,服务端将接受到的客户端发来的文件存储到本地之后并返回一个发送成功给客户端,并关闭相应的连接
package 网络编程.TCP网络编程;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Server2 {
/*
这里我们实际编程中应该是要使用try --- catch --- finally来解决异常,但是我们这里为了思路清晰就
使用了throws + 异常对象的方式将异常对象进行了抛出
*/
public static void main(String[] args) throws IOException{
/*
创建ServerSocket类的对象,客户端是创建Socket,而服务器端是创建ServerSocket对象
注意 : 创建ServerSocket对象也会抛出IOException
*/
ServerSocket ss = new ServerSocket(9090);
/*
使用ServerSocket类的对象调用accept()方法获取客户端传输的Socket对象
*/
Socket socket = ss.accept();
/*
获得客户端Socket对象对应的输入流
*/
InputStream is = socket.getInputStream();
/*
创建一个字节输出流,将客户端传输过来的文件写出到异常中
*/
FileOutputStream fos = new FileOutputStream(new File("hi.png"));
/*
创建一个缓冲数组
*/
byte [] buffer = new byte[1024];
/*
创建一个临时变量 -- 用于存储read()方法的返回值
*/
int len = 0;
/*
使用客户端传输过来的Socket对应的输入流将数据读入内存之后又使用字节输出流将内存中的文件写出到硬盘中
*/
while((len = is.read(buffer))!= -1){
fos.write(buffer,0,len);
}
/*
服务器端给客户端给出提示
*/
OutputStream os2 = socket.getOutputStream();
os2.write("发送成功".getBytes());
/*
流资源的关闭
*/
fos.close();
is.close();
socket.close();
ss.close();
os2.close();
}
}
- 其次这里我们再给出客户端的程序
package 网络编程.TCP网络编程;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
public class Client2 {
//注意: 实际编程中我们应该是使用try --- catch --- finally将异常处理掉,但是这里我们为了思路的清晰使用了throws + 异常对象将异常抛出了
public static void main(String[] args) throws IOException{
//创建Socket对象,Socket对象作为网络传输的节点,我们要给客户端的Socket中封装有目标的IP地址+端口号
/*
注意: 我们创建Socket对象的时候会抛出IOException
不管我们使用Socket类的构造器或者是使用ServerSocket类对象调用accept()方法得到Socket对象都会有IOException
*/
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),9090);
/*
获取对应Socket对象的输出流,用于将文件发送给服务器端
*/
OutputStream os = socket.getOutputStream();
/*
创建一个字节输入流,将我们的图片文件"abc.png"读取到内存中来,后面再使用Socket对象的输出流将文件传输给服务器端
*/
FileInputStream fis = new FileInputStream(new File("abc.png"));
/*
创建缓冲数组
*/
byte [] bytes = new byte[1024];
/*
创建临时变量存储read()方法的返回值
*/
int len = 0;
/*
使用字节输入流对象将文件从硬盘中读取到内存中,然后使用Socket对象对应的输出流将文件输出
*/
while((len = fis.read(bytes))!=-1){
os.write(bytes,0,len);
}
/*
由于我们的read()方法时阻断式的方法,一次一个输入流对象只能有一个read()方法在进行
并且这个时候我们的Socket对应的输出流写出文件没有一个具体的停止的时机,这个时候我们的服务端中的
Socket对应的输入流的read()就会一直执行,一直在等待这个输出流写出数据,这个时候就一直卡到这个read()方法处
后面的客户端中的Socket对应的read()方法也不会执行,因为同时一个输入流对象只可以有一个read()方法在
执行
那么这个时候我们就要想办法让我们的输入流停下来,这个时候我们又两种办法,一种是让前面的Socket对应的输出流停止输出
还有一种就是让这个read()停止输入,但是让read()
注意: 这个时候就要视情况而定了,我们一般都是让关闭前面Socket对应的输出流 -- 也就是在这里调用shutdownOutput()方法;
*/
socket.shutdownOutput();
/*
获取socket对象对应的输入流对象
*/
InputStream is2 = socket.getInputStream();
/*
创建一个ByteArrayOutputStream类的对象 , 防止出现byte[]数据转换为String时出现乱码
*/
ByteArrayOutputStream boas = new ByteArrayOutputStream();
/*
创建一个缓冲数组
*/
byte [] buffer = new byte[1024];
/*
创建一个临时变量,用于存储read()方法的返回值
*/
int len2 = 0;
while((len2 = is2.read(buffer))!=-1){
/*
使用了ByteArrayOutputStream类的write()方法,
会讲要输出的byte[]类型的数据先整体存储到一个恨大的数组中,然后一次性输出
*/
boas.write(buffer,0,len2);
}
//调用ByteArrayOutputStream类的toString()方法进行输出
System.out.println(boas);
/*
流资源的关闭
*/
os.close();
fis.close();
socket.close();
}
}
补充:
-
输入流的read()方法是一个阻断式的方法
- 一个输入流对象同时只能有一个read()方法在执行
-
我们可以通过调用Socket类中的shutdownOutput()方法来显示的,明确的关闭某个Socket类的对象对应的输出流
- 当然调用shutdownInput()方法同样可以关闭输入流