目录Java完成Socket文件传输Java Socket数据传输基础以及优化UDP和TCP Socket使用方法总的应用代码,图片传输代码中需要注意的点总结Java完成Socket文件传输TCP协议的Socket文件传输分别使用三个类(TCPFileUpload_Server服务器端、TCPFileUpload_Client客户端、StreamUtils工具类)完成图片的传输。
同样先运行服务器端文件,再运行客户端文件import java.io.*;import java.net.ServerSocket;import java.net.Socket;/*** 服务器端*/ public class TCPFileUpload_Server {public static void main(String[] args) throws Exception {//思路//在本机 的8888端口监听, 等待连接ServerSocket serverSocket = new ServerSocket(8888);System.out.println("服务器端,监听8888端口,等待连接");//当没有客户端连接8888端口时,程序会 阻塞, 等待连接//如果有客户端连接,则会返回Socket对象,程序继续Socket socket = serverSocket.accept();//通过socket.getInputStream() 读取客户端写入到数据通道的数据, 并转换成字节数组BufferedInputStream bufferedInputStream = new BufferedInputStream(socket.getInputStream());byte[] bytes = StreamUtils.streamToByteArray(bufferedInputStream);//写入指定路径BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("src\\G.jpg"));bufferedOutputStream.write(bytes);//关闭IO流bufferedOutputStream.close();//向客户端回复收到图片BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bufferedWriter.write("收到图片!");bufferedWriter.flush();socket.shutdownOutput();//关闭所有流bufferedWriter.close();bufferedInputStream.close();socket.close();serverSocket.close();}}import java.io.*;import java.net.InetAddress;import java.net.Socket;/*** 客户端*/ public class TCPFileUpload_Client {public static void main(String[] args) throws Exception {//连接服务端 (ip , 端口)
//解读:连接本机的 8888端口, 如果连接成功,返回Socket对象Socket socket = new Socket(InetAddress.getLocalHost(), 8888);System.out.println("客户端 连接端口:" + socket.getPort());//创建读取磁盘文件IO流BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("src/P.jpg"));//获取字节数组byte[] bytes = StreamUtils.streamToByteArray(bufferedInputStream);//通过Socket获取到输出流,将bytes发送到服务端BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream());bufferedOutputStream.write(bytes);//关闭流对象,socket,刷新,添加终止符bufferedInputStream.close();bufferedOutputStream.flush();socket.shutdownOutput();//接受回复消息//此处可调用Utils的方法// String s = "";// while ((s = bufferedReader.readLine()) != null)// System.out.println(s);System.out.println(StreamUtils.streamToString(socket.getInputStream()));//关闭所有流bufferedOutputStream.close(); //socket的包装流不要过早关闭socket.close();}}import java.io.BufferedReader;import java.io.ByteArrayOutputStream;import java.io.InputStream;import java.io.InputStreamReader;/*** 此类用于演示关于流的读写方法*/ public class StreamUtils {/*** 功能:将输入流转换成byte[]** @param is 输入流* @return byte数组* @throws Exception IO流异常*/ public static byte[] streamToByteArray(InputStream is) throws Exception {ByteArrayOutputStream bos = new ByteArrayOutputStream();//创建输出流对象byte[] b = new byte[1024];int len;while ((len = is.read(b)) != -1) {bos.write(b, 0, len);}byte[] array = bos.toByteArray();bos.close();return array;}/*** 功能:将InputStream转换成String** @param is 输入流* @return 字符串* @throws Exception IO流异常*/ public static String streamToString(InputStream is) throws Exception {BufferedReader reader = new BufferedReader(new InputStreamReader(is));StringBuilder builder = new StringBuilder();String line;while ((line = reader.readLine()) != null) { //当读取到 null时,就表示结束builder.append(line + "\r\n");}return builder.toString();}}Java Socket数据传输基础以及优化学到Java的TCP的Socket传输数据有些错误和心得在此记下UDP和TCP
UDP:
无连接通信协议,数据的发送端和接收端不用构建逻辑连接(发送时发送端无需确认接收端的存在,接收端无需返回相映给发送端)
UDP协议资源消耗小,通信效率高,通常用于音频、视频接收和普通数据的传输但是又因为UDP面向无连接性,不能保证数据的完整性,因此在传输重要数据的时候不推荐使用UDP协议
TCP:
在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠性第一次握手:客户端向服务器发出连接请求第二次握手:服务器通知客户端收到了连接请求第三次握手:客户端再次向服务器发送确认信息,确认连接TCP的传输安全性高于UDP,下载文件和浏览网页等使用的都是TCP TCP的socket通信一种情况:客户端发送信息和接收信息需要输入输出流两个流,同理服务器也是这样,为了避免生成许许多多的流对象,所以可以利用socket中自带的输入输出流进行数据交互Socket使用方法
1.客户端
构造函数 Socket socket = new Socket(ip,port); 注解: 因为TCP是逻辑连接式的传输,所以客户端需要得知服务器的ip和端口使用getOutputStream() 方法获得输出流OutputStream cos = socket.getOutputStream();cos.write("你好服务器".getBytes()); 注解:write使用字节输入输出,需要经过 字符–字节–字符的转换,转换的方法getBytes() ,new String(buf,0,len) ,如果想要直接输出可以使用打印流printStream使用getInputStream方法获得输入流InputStream cis = socket.getInputStream()//设置一个缓冲数组 temp数组大小大于所接收的数据量byte[] temp = new byte[1024];int len = cis.read(temp);//将所接守的字节转换为字符串 这里使用 temp.toString()会有乱码System.out.println(new String(temp,0,len));注意最后要释放资源socket.close();
2.服务器
服务器首先要创建ServerSocket设置端口号ServerSocket server = new ServerSocket(port:8888);注解:注意当编写循环响应时server的定义需要在while(true)循环之外,不然会显示端口被占用的情况Exception in thread "main" java.net.BindException: Address already in use: NET_Bind然后使用accept()方法返回Socket对象Socket socket = server.accept();accept() 方法具有阻塞作用,后面的实例会提到通过accept()获得socket对象后,后面的操作方式与客户端的socket其实是一致的了//获得流对象InputStream sis = socket.getInputStream();OutputStream sos = socket.getOutputStream();//打印从客户端获得的数据byte[] temp = new btye[1024];sis.read(temp);System.out.println(new String(temp));//对客户端发出返回信息sos.write("你也好,客户端".getBytes());注意最后要释放资源socket.close();server.close();总的应用代码,图片传输客户端import java.io.*;import java.net.*;public class TCPClient {public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("C:\\Users\\子陌\\Pictures\\1.jpg");Socket socket = new Socket("192.168.1.8",8888);OutputStream cos = socket.getOutputStream();InputStream cis = socket.getInputStream();int len =0;byte[] bytes = new byte[1024];while((len = fis.read(bytes))!=-1){cos.write(bytes,0,len);}socket.shutdownOutput();byte[] bytes1 = new byte[1024];int len1=0;len1 =cis.read(bytes1);System.out.println(new String(bytes1));socket.close();fis.close();}}服务器import java.io.*;import java.net.ServerSocket;import java.net.Socket;import java.util.Random;public class TCPSever {public static void main(String[] args) throws IOException {//这里ServerSocket要放到外面ServerSocket server = new ServerSocket(8888);while(true) {new Thread(new Runnable() {@Override public void run() {try{//先把accept响应放到前面Socket socket = server.accept();String fileName = "itcast" + System.currentTimeMillis() + new Random().nextInt();File file = new File("D:\\TCPUpLoad");if (!file.exists()) {file.mkdirs();}FileOutputStream fos = new FileOutputStream(file + "\\" + fileName + ".jpg");//这里file既是File类也可以当作路径名称//FileOutPutStream 会自动生成空文件InputStream sis = socket.getInputStream();OutputStream sos = socket.getOutputStream();int len = 0;byte[] bytes = new byte[1024];while ((len = sis.read(bytes)) != -1) {fos.write(bytes, 0, len);}sos.write("已经收到".getBytes());socket.close();fos.close();//重点:要将资源全部释放,不然会占用线程或者端口}catch(IOException e){System.out.println(e);}}}).start();}//server.close();}}代码中需要注意的点1.服务器ServerSocket需要放到while外部,while的目的是能够随时响应客户端的请求2.fileName 使用了String fileName = "itcast" + System.currentTimeMillis() + new Random().nextInt(9999); 这也就是为什么从网上下载的图片有一大堆数字名字的原因
3.利用了多线程重写Runnable中的
run 方法,运用了匿名内部类,大大提高了服务器的响应速度
4.这里涉及之前提到的一个容易出bug的问题,
server.accept() 的阻塞作用,因为会服务器会不断的while循环就会开启很多线程,如果FileOutStream fos = new FileOutStream(...) 运行先于server.accept(),就会每产生一个线程就创建一个空文件我就是犯了这个错误导致电脑多了几万个带.jpg的空文件5.服务器和客户端要同时运作时需要知道自己的ip地址,可以在运行的cmd 中 输入ipconfig 进行查询6.Runnable 中的run 方法并不能自动抛出异常,只能手动try catch详见上方代码7.还有一个阻塞问题就是,当客户端读取结束后传输给服务器,但是服务器并不知道读取结束就会导致客户端和服务器的同时阻塞,这时需要Socket 中的shutdownOutput() 方法告诉服务器已经读取完毕 while((len = fis.read(bytes))!=-1){cos.write(bytes,0,len);}socket.shutdownOutput();总结以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
您可能感兴趣的文章:Java如何利用Socket传输信息或文件java socket大数据传输丢失问题及解决解决DataInputStream read不等于-1,socket文件传输只能传输一个文件无法传输多个问题
