服务器端(ServerSocket)
先贴源码
package javaSE_exise.网络编程;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class 文件接收服务器 {
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(8888)) {
while (true) {
Socket cilentSocket = serverSocket.accept();
InetAddress address = serverSocket.getInetAddress();
System.out.println(address + "正在上传文件");
// 图片名称
String imgName = address.getHostAddress().replace(".", "-").concat(".jpg");
try (BufferedInputStream bis = new BufferedInputStream(cilentSocket.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\Codes\\Java_works\\excise-basic\\src\\javaSE_exise\\网络编程\\图片上传文件夹"+"\\"+imgName));
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(cilentSocket.getOutputStream()))) {
byte[] bytes = new byte[2048];
int len = -1;
while((len = bis.read(bytes))!=-1){
bos.write(bytes, 0, len);
}
bos.flush();
bufferedWriter.write("上传成功");
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
要点如下:
1.new ServerSocket(你的端口号),调用accept()方法时候也就是启动服务器时候,如果没有被请求,则是阻塞状态,被请求以后会返回请求主机的socket。
2.图像名称就是把主机号的 . 改为 - 并且命名为 .jpg。
3.输入流是从网络输入过来的,所以cilentSocket调用.getInputStream()方法并且封装为效率更高的BufferedInputStream对象。
4.输出流输出的字节,是由文件字节流实例的,所以先实例出FileOutputStream(需要输出的文件路径),再用FileOutputStream去实例效率更高的BufferedOutputStream对象。
5.上传成功后需要发消息给客户端,自然需要字符输出流BufferedWriter对象,但流中的数据都是字节,需要使用OutputStreamWriter来转化成字符流,OutputStreamWriter中的字节数据来自于cilentSocket对象的输出流,所以使用cilentSocket中的getOutputStream()方法获得cilentSocket的输出流来实例OutputStreamWriter。
客户端cilentSocket
代码如下:
package javaSE_exise.网络编程;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
public class 文件发送 {
public static void main(String[] args) throws UnknownHostException, IOException {
try (Socket socket = new Socket("192.168.199.156", 8888);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\ZH\\Pictures\\头像壁纸\\头像.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());) {
byte[] bytes = new byte[2048];
int len = -1;
while ((len = bis.read(bytes)) != -1) {
bos.write(bytes,0,len);
}
bos.flush();
socket.shutdownOutput();
String line = bufferedReader.readLine();
System.out.println(line);
}
}
}
要点如下:
1.实例套接字Socket时候需要两个参数,第一个是目标主机ip,第二个是目标主机监听的端口号。
2.首先发送文件首先要考虑的是输入流,毕竟想上传文件,先得把文件流进来,才能经过java的逻辑流出去。想要读(流入)文件就需要FileInputStream(你的文件地址),又因为效率低,再通过BufferedInputStream包装FileInputStream。
3.其次,就要考虑流出,也就是发送文件的问题,通过网络发送那就直接使用套接字,socket中的getOutputSteam()方法获得输出流,同样的效率低下,使用BufferedOutputStream包装提升新能。
4.还要考虑服务器给客户端发消息的问题,消息使用字符输入流最方便性能也很棒,并且消息通过网络传递,所以使用套接字socket中的getInputStream()方法获得输入流,这种输入流是字节输入流,我们要转化成字符输入流,就要使用当前输入流去实例InputStreamReader对象,这样就转成了字符流,但是性能较差可用方法较少读起来比较麻烦,再用字符流实例化缓冲区字符流BufferedReader对象即可。
5.最需要注意的是当所有的文件以字节形式存在内存中,也就是缓冲区时,我们清空缓冲区,发送了但是服务器端并不会读取消息,因为服务器不确定客户端还有没有要发送的流,所以并不会读,我们需要在发送结束后,要用socket对象来暂时结束输出流,也就是告诉服务器端,我的流发送结束了,你可以读了。这样服务器端才会读取客户端发送的流。