本篇主要是一些案列的实现
案例1
思路图
代码
服务端
package yuan.hsp.net.TranFile;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
@SuppressWarnings({"all"})
public class Server {
public static void main(String[] args) throws UnknownHostException, IOException {
//服务端叫ServerSocket,在8888端口监听
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("在8888端口等待链接");
//等待链接
Socket accept = serverSocket.accept();
//先创建这个输入流,读取数据,处理流包
BufferedInputStream In = new BufferedInputStream(accept.getInputStream());
//由于我们之前已经写了输入流变成字符数组的方法直接用
byte[] STA = StreamUtils.StreamTOByteArray(In);
//(相对路径)创建输出流输出文件,还是处理流包
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("src\\66.png"));
bos.write(STA);//写入
System.out.println("服务端传输文件完成");
//然后介绍输出客户端:收到图片
BufferedWriter b = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
b.write("收到图片");
b.flush();//这个底层才是发送数据
accept.shutdownInput();//如果用这个作为停止标志,那么接收方是可以用字节流接收字符流传输的数据的
//这两个流也要最后关闭,不然你写入的数据Cilent读不到,不知道为啥,感觉写网络就最后把流都关闭一下吧
In.close();
bos.close();
b.close();
accept.close();
serverSocket.close();
System.out.println("服务端退出");
}
}
客户端
package yuan.hsp.net.TranFile;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
@SuppressWarnings({"all"})
//传输文件客户端
//这里我写一个工具类StreamUtils,具体作用自己去看
public class Cilent {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket(InetAddress.getLocalHost(),8888);
byte [] b=new byte[1024];//创建字节接收文件
//创建一个把文件输入到我们客户端的流,用处理流包下文件节点流
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("d:\\ykj.png"));
//运用工具类,把我们的字节输入流输入的数据转为字节数组
byte[] streamTOByteArray = StreamUtils.StreamTOByteArray(bufferedInputStream);
//创建向服务端输送数据的流,这里还是用到这个处理流反正以后就用处理流就对了
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
bos.write(streamTOByteArray);//写入字节数组
bufferedInputStream.close();//可以把那个文件输入流关闭了
socket.shutdownOutput();//注意,字节流输入要这个结束标记
InputStream inputStream = socket.getInputStream();//还是我们能把一个输入数据转换为字节数组,就那个工具类,既然写了就多用
System.out.println(new String(StreamUtils.StreamTOByteArray(inputStream)));
//关闭
bos.close();//注意,这个不要中间关闭,会报错
socket.close();
System.out.println("客户端退出");
}
}
工具类(输入字节流转换为字节数组)
package yuan.hsp.net.TranFile;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
//工具类
public class StreamUtils {
public static byte[] StreamTOByteArray(InputStream i) throws IOException {//接收一个输入流对象,把这个对象传输的数据转换为一个字节数组
//创建一个字节数组输出流,因为最后可以转换成一个字节数组
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte b[]=new byte[1024];
int len;
while((len=i.read(b))!=-1) {
byteArrayOutputStream.write(b,0,len);
}
byte[] array=byteArrayOutputStream.toByteArray();
byteArrayOutputStream.close();
return array;
}
}
对应效果
服务端
客户端
文件传输效果
注意:等到最后再把所有流一起close,不然会出现许多难以想象的错误
关于TCP网络通讯的小秘密
就是客户端也会分配一个端口来和程序段连接
程序验证(netstate)
用我们上面写的程序,可以直接运行服务端
然后
关于本机8888端口只有这一个
如果运行客户端
除了上面那个
还会多一个这个,注意我们在本机netstat查看网络状况,是以本机为服务端的!
然后我们的服务端是8888端口
这个60285端口其实就是客户端随机分配的端口
服务器端口是创建ServerSocket就确定的
客户端就是TCP/IP随机分配的
小知识
byte[] b这样直接b.toString()
是不能显示我们原本的内容的(如果有中文)
需要new String(b,0,len)
具体可以看
关于new String(byte [])和byte[].toSring()和Arrays.toString(byte [])的区别
还有只要是Buffered用了处理流,不过你是字节流还是字符流,只要是输出的流,你想写入都要flush()不然不会写入成功
下面这个例子就是惨痛教训
案列2
客户端
package yuan.hsp.net.TranFile;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
@SuppressWarnings({"all"})
//文件下载客户端
public class downloadCilent {
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(),6666);
Scanner scanner = new Scanner(System.in);
System.out.println("输入你想要下载的歌");
String next = scanner.next();
BufferedOutputStream outputStream = new BufferedOutputStream(socket.getOutputStream());
outputStream.write(next.getBytes());
outputStream.flush();//注意只要用处理流,最后一定要刷新!!!
//还要注意一定要结束!!!
socket.shutdownOutput();
byte[] streamTOByteArray = StreamUtils.StreamTOByteArray(socket.getInputStream());
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(
new FileOutputStream("d:\\喜欢的音乐.mp3"));
bufferedOutputStream.write(streamTOByteArray);
bufferedOutputStream.close();
socket.close();
scanner.close();
System.out.println("客户端退出");
}
}
服务端
package yuan.hsp.net.TranFile;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.channels.NonWritableChannelException;
import java.util.Scanner;
import yuan.learn.basic.Multithreading.interrupt_;
@SuppressWarnings({"all"})
//文件下载服务端
public class downloadServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(6666);
System.out.println("服务端在6666端口等待");
Socket accept = serverSocket.accept();
BufferedInputStream InputStream = new BufferedInputStream(accept.getInputStream());
byte[] array = StreamUtils.StreamTOByteArray(InputStream);
String Array = new String(array, 0, array.length);
System.out.println("需要查找的文件是"+Array);
//传输文件肯定是字节流
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(accept.getOutputStream());
String name = "";
if(Array.equals("Ferrari")) {
name="d:\\CloudMusic\\Bebe Rexha - Ferrari.mp3";
}
else {
name="d:\\CloudMusic\\周星星 - 足够.mp3";
}
BufferedInputStream bufferedInputStream = new BufferedInputStream(
new FileInputStream(name));
byte[] Array02 = StreamUtils.StreamTOByteArray(bufferedInputStream);
bufferedOutputStream.write(Array02);
accept.shutdownOutput();
//关闭,后开的资源先关闭
bufferedInputStream.close();
bufferedOutputStream.close();
accept.close();
serverSocket.close();
System.out.println("服务端退出");
}
}
运行结果
服务端
客户端
惨痛教训主要就是
1.服务端卡着不动-因为没有设计客户端输出结束标志(socket.shutdownOutput)
2.输出的文件是乱码,用byte[].toString(),这个方法本质是是用的Object所以没有重写就是原来那个字节数组
3.换成new String后,文件输出为空白
主要是处理流(不管是字节还是字符)都要flush()我没有写flush()然后就没有成功写入