1)找到IP地址
2)必须有端口
3)必须有协议(TCP协议,UDP协议)
举例:
我想和高圆圆说话...
1)我首先要找到她...需要知道的位置(IP)
2)找到了她之后,怎么跟她说话?对着她的耳朵说话....
3)找到她了,对着她的说:
i love you ....
高圆圆听不懂英语...(协议)
中文:我爱你
1.IP地址:
PC机器都有唯一的标识:ip
ip地址:192.168.1.100 已经优化的ip
ip每一个段落转成二进制:
11000000 10101000 00000001 01100100
192 168 1 100
ip如果每次写成二进制数据,非常麻烦,所以采用点分十进制法,将每一个二进制数据转成十进制数据,中间用.隔开
常见的IP:
A类:1.0.0.1---127.255.255.254:第一个号段为网络号段,后三个号段为主机号段
256^3=16777216台计算机 (强大的部门),通常:国防部(美国的五角大楼)
B类:128.0.0.1---191.255.255.254:前两个号段为网络号段,后两个号段为主机号段()
256^2: 通常大学里面或者一些地方政府部门
C类:192.0.0.1---223.255.255.254:前三个好号段为网络号段,后一个号段为主机号段
192.168.1.100(私人地址:家庭或者单位)
D类 224.0.0.1---239.255.255.254
E类 240.0.0.1---247.255.255.254
127.0.0.1:回环地址(也可表示本机地址)
xxx.xxx.xxx.255:广播地址
常用的命令:
ipconfig:查看ip
ping ip地址:查看当前本机与这台Pc机器的网络通信
原理和声呐系统是一样的
2.端口:如果一台Pc机器想要和另一台进行通信的话,光有ip是不行的,还必须知道端口号是多少
计算机中每一个软件都它有自己的的端口号:通过360查看每个软件的对应应用程序的端口号
有效端口号:0~65535
保留端口号:0~1024
3.协议:
TCP协议和UDP协议 区别:
TCP协议:(客户端和服务器端的交互)
1)建立连接通道(通道内的流:(使用的是最基本的字节流))
2)可靠协议
3)由于可靠协议,并且需要建立连接通道(服务器端需要等待客户端连接),执行效率低
4)使用TCP协议(TCP编程)可以发送大量的数据,文件大小无限制
UDP协议:(发送端和接收端)
1)无需建立连接通道(数据报包的形式发送数据的)
2)不可靠协议
3)由于不可靠,无需建立连接通道,所以它的执行效率高
4)UDP协议(UDP编程)发送数据有限制
thunder://
http://
ftp://
file://
mail:
二.网络编程
1. InetAddress类:
该类没有构造方法,表示互联网协议 (IP) 地址。
如果一个类中没有构造方法:
A:这个类里面的成员方法都是静态(Math,Arrays,Collections)
B:单例模式(设计模式):在内存始终只有一个对象
将构造方法私有化
在成员变量创建该类的实例(并且这个实例私有化被static修身)
提供该类公共方法可以通过外界调用
C:该类中会某些 静态成员方法的返回值是该类本身(InetAddress就是一个例子)
public class Demo{
private Demo(){
}
public static Demo get(){
return new Demo() ;
}
} ,,,,,
例子:
public class InetAddressDemo {
public static void main(String[] args) throws UnknownHostException {
//public static InetAddress getByName(String host)throws UnknownHostException在给定主机名的情况下确定主机的 IP 地址
//该主机名可以是计算机名(PC机器的计算机名称),也可以是ip地址的文本表现形式,通过这个方法返回的是ip地址对象
// InetAddress address = InetAddress.getByName("USER-20171205ZR") ;
InetAddress address = InetAddress.getByName("192.168.10.101") ;
// System.out.println(address);//USER-20171205ZR/192.168.10.101
//如何通过得到的addressIp地址对象来得到当前计算机名称
//public String getHostName()获取此 IP 地址的主机名。
//如果此 InetAddress 是用主机名创建的,则记忆并返回主机名
String name = address.getHostName() ;
System.out.println("name:"+name);
//获取具体的ip地址文本形式
//public String getHostAddress()返回 IP 地址字符串(以文本表现形式)。
String ip = address.getHostAddress() ;
System.out.println("ip:"+ip);//192.168.10.101
}
}
2.UDP协议
UDP协议(发送端和接收端),不需要建立连接通道
发送端
步骤:
1)创建UDP协议发送端的Socket对象
2)创建数据报包:通过这个数据包将数据发送到接收端
3)调用UDP协议发送端发送的方法
4)关闭资源
例子:
public class SendDemo {
public static void main(String[] args) throws Exception {
//使用UDP协议创建Socket对象不是Socket类对象,(客户端的套接字)
//DatagramSocket:用来发送和接收数据报包的套接字。
//public DatagramSocket() throws SocketException
DatagramSocket ds = new DatagramSocket() ;//创建了UDP协议的Socket对象
//发送一句话
String str = "hello,udp,i'm coming" ;
//2)创建数据报包对象
// public DatagramPacket(byte[] buf, int length ,InetAddress address,int port)
//将字符串数据转换成字节数组
byte[] bys = str.getBytes() ;
//当前字节数组的实际长度
int len = bys.length ;
//创建InetAddress对象,Ip地址对象
InetAddress address = InetAddress.getByName("192.168.10.101") ;
//指定端口号:0-65535是有效端口号
int port = 10086 ;
DatagramPacket dp = new DatagramPacket(bys, len, address, port) ;
//3)调用UDP协议DataScoket类里面发送的方法
//public void send(DatagramPacket p) throws IOException从此套接字发送数据报包
ds.send(dp) ;
//4)关闭资源
ds.close() ;
}
}
UDP协议的接收端
1)创建接收端的Socket对象
2)创建一个数据报包接收发送端发送来的数据报包(接收容器)
3)接收数据,调用DataScoket类中的接收的方法来接收数据包
4)解析数据报包里面的实际数据,显示在控制台上
5)关闭资源
多次运行接收端,会出现一处:BindException:绑定异常:
接收端运行一次就可以了,端口号已经被占用了,不能再继续使用这个端口号
例子:
public class ReceiveDemo {
public static void main(String[] args) throws IOException {
//public DatagramSocket(int port)
//1)创建UDP协议接收端的scoket对象
DatagramSocket ds = new DatagramSocket(10086) ;
//2)创建数据报包:DatagramPacket,来接收发送端发送来的数据
//public DatagramPacket(byte[] buf,int length)构造 DatagramPacket,用来接收长度为 length 的数据包。
//定义字节数组:缓存区
byte[] bys = new byte[1024] ;
DatagramPacket dp = new DatagramPacket(bys, bys.length) ;
//3)调用DataScoket里面接收的方法
// public void receive(DatagramPacket p) throws IOException从此套接字接收数据报包
ds.receive(dp) ;// 阻塞式方法(等待发送端发送数据,只要没有数据,就一直等待,有数据的话将数据显示控制)
//4)4)解析数据报包里面的实际数据,显示在控制台上
//获取到ip字符串表现形式
//public InetAddress getAddress():首先通过数据报包得到一个Ip地址对象:InetAddress
InetAddress address = dp.getAddress() ;
//可以通过getHostAddress()得到ip地址的文本形式
String ip = address.getHostAddress() ;
//解析发送端发送来的实际数据
// byte[] getData() 返回数据缓冲区。
// int getLength() 返回将要发送或接收到的数据的长度。
byte[] dataBys = dp.getData() ;
//获取数据缓存区中的实际长度
int len = dp.getLength() ;
//将字符串显示出来
String str = new String(dataBys,0,len) ;
//输出到控制台
System.out.println(ip+":给你发送了:"+str);
}
}
发送端的数据来源不是简单的一条语句而是不停的键盘录入
键盘录入的方式:
1)Scanner类
2)BufferedReader类(字符缓冲流)特有功能:readLine():一次读取一行 (System.in)
快船,QQ
需求:接收端和发送端是在两个窗口中显示的,如何让这两个接收端和发送端处于一个窗口下(main中)
(使用多线程第二种方式:Runable接口的方式实现 发送端和接收端处于一个主线程中)
接收端不停的接收键盘录入的数据显示到控制台上
public class ReceiveTest {
public static void main(String[] args) throws IOException {
//创建接收端的socket对象
DatagramSocket ds = new DatagramSocket(12345) ;
while(true){
byte[] bys = new byte[1024] ;
DatagramPacket dp = new DatagramPacket(bys, bys.length) ;
//接收数据
ds.receive(dp) ;
//获取ip字符串的表现形式
String ip = dp.getAddress().getHostAddress() ;
//解析数据接收容器,获取里面实际的内容
byte[] buff = dp.getData();
int len = dp.getLength() ;//获取实际数据缓冲区实际长度
String s = new String(buff, 0, len) ;
//显示到控制台
System.out.println("from" + ip +"data is :"+s);
// //释放资源,为了模仿一直有发送端发送来的数据,所以无需关闭接收端Socket
// ds.close() ;
}
}
}
public class SendTest {
public static void main(String[] args) throws IOException {
//创建发送端的Socket对象
DatagramSocket ds = new DatagramSocket() ;
//以IO流的读取键盘录入的数据发送到接收端
//字符缓冲流
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;
//一次读取一行
String line = null ;
while((line=br.readLine())!=null){
//发送端不停的发送数据应该有一个结束条件
//自定义结束条件
if("886".equals(line)){
break ;
}
//创建数据报包
//DatagramPacket(byte[] bys,int length,InetAddrss address,int port)
byte[] bys = line.getBytes() ;
DatagramPacket dp = new DatagramPacket(bys, bys.length,
InetAddress.getByName("192.168.10.101"), 12345);
//发送数据
ds.send(dp) ;
}
//释放资源
ds.close() ;
}
}
需求:接收端和发送端是在两个窗口中显示的,如何让这两个接收端和发送端处于一个窗口下(main中)
(使用多线程第二种方式:Runable接口的方式实现 发送端和接收端处于一个主线程中)
public class ChatRoom {
public static void main(String[] args) {
try {
//发送端和接收端分别自定义类表示发送端线程和接收端线程
//SendThread,receiveThread
//需要有两个Socket对象
//创建发送端和接收端的Socket对象
DatagramSocket sendSocket = new DatagramSocket() ;
DatagramSocket receiveSocket = new DatagramSocket(8888) ;
//创建资源对象
SendThread st = new SendThread(sendSocket) ;
ReceiveThread rt = new ReceiveThread(receiveSocket) ;
//创建线程类对象
Thread t1 = new Thread(st) ;
Thread t2 = new Thread(rt) ;
//启动线程
t1.start() ;
t2.start() ;
} catch (SocketException e) {
e.printStackTrace();
}
}
}
public class SendThread implements Runnable {
//定义一个变量
private DatagramSocket ds ;
public SendThread(DatagramSocket ds){
this.ds = ds ;
}
@Override
public void run() {
try {
//创建发送端Socket对象
//以Io流的读取键盘录入的数据
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;
String line = null ;
while((line=br.readLine())!=null){
//结束条件
if("over".equals(line)){
break ;
}
创建数据报包
byte[] bys = line.getBytes() ;
DatagramPacket dp = new DatagramPacket(bys, bys.length,
InetAddress.getByName("192.168.10.101"), 8888) ;
//发送数据
ds.send(dp) ;
}
//释放资源
} catch (Exception e) {
e.printStackTrace();
}finally{
//释放资源
if(ds!=null){
ds.close() ;
}
}
}
}
public class ReceiveThread implements Runnable {
private DatagramSocket ds ;
public ReceiveThread(DatagramSocket ds){
this.ds =ds ;
}
@Override
public void run() {
//创建接收端的socket对象
try {
while(true){
byte[] bys = new byte[1024] ;
DatagramPacket dp = new DatagramPacket(bys, bys.length) ;
//接收数据
ds.receive(dp) ;
//获取ip字符串的表现形式
String ip = dp.getAddress().getHostAddress() ;
//解析数据接收容器,获取里面实际的内容
byte[] buff = dp.getData();
int len = dp.getLength() ;//获取实际数据缓冲区实际长度
String s = new String(buff, 0, len) ;
//显示到控制台
System.out.println("from" + ip +"data is :"+s);
}
//接收要不停接收数据,不需要关闭
} catch (IOException e) {
e.printStackTrace();
}
}
}
3.TCP协议
使用Socket编程里面的TCP协议
客户端和服务器端的交互
客户端步骤:
1)创建客户端的socket对象 (客户端套接字流的形式)
2)获取通道的内流(输出流)
3)使用输出流对象写数据
4)关闭客户端的Socket对象
对于TCP协议来说:客户端和服务器端是需要建立连接通道的,如果没有启动服务器端,先启动客户端:
报异常:java.net.ConnectException
Connection refused: connect :连接被拒绝!
public class ClientDemo {
public static void main(String[] args) throws IOException {
//1)1)创建客户端的socket对象:此类实现客户端套接字
//构造方法:Socket类
//public Socket(InetAddress address, int port)
//throws IOException创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
// Socket s = new Socket(InetAddress.getByName("192.168.10.101"), 10010) ;
//public Socket(String host, int port)
//host:可以是主机名称也可是ip地址的字符串表现形式
Socket s = new Socket("192.168.10.101", 10010) ;
//2) 获取通道的内流(输出流)
//public OutputStream getOutputStream()
//throws IOException返回此套接字的输出流。
OutputStream out = s.getOutputStream() ;
//3)客户端通道内的流给服务器写数据
out.write("hello,TCP,我来了...".getBytes()) ;
//4)关闭客户端socket
s.close() ;
}
}
TCP协议的服务器端
1)创建服务器端的socket对象,指定端口
2)服务器端需要监听客户端的连接
3)获取通道内的输入流
4)将数据获取到并显示到控制台
5)关闭服务器端的socket资源
public class ServerDemo {
public static void main(String[] args) throws IOException {
//1)ServerSocket此类实现服务器套接字。服务器套接字等待请求通过网络传入
//public ServerSocket(int port) 构造方法:创建绑定到特定端口的服务器套接字
ServerSocket ss = new ServerSocket(10010) ;
System.out.println("等待客户端连接...");
//2)监听客户端的连接:请求等待介入
//public Socket accept()
// throws IOException侦听并接受到此套接字的连接
//该方法特点:服务器在连接到客户端之前,此方法一直处于阻塞
Socket s = ss.accept() ;//一旦客户端那边也是端口,阻塞式方法就会结束
System.out.println("客户端已经连接...");
//3)获取通道内的输入流对象
//public InputStream getInputStream()
InputStream in = s.getInputStream() ;
//4)将客户端发送的数据显示到控制台上
//定义一个缓冲数组
byte[] bys = new byte[1024] ;
int len = in.read(bys) ;//获取到实际的字节数 (阻塞式)
String str = new String(bys, 0, len) ;
//获取IP地址的文本形式
// public InetAddress getInetAddress()返回套接字连接的地址。
InetAddress address = s.getInetAddress() ;
//在通过ip地址对象getHostName();
String ip = address.getHostAddress() ;
//输出显示到控制台
System.out.println(ip+"传递的数据是:"+str);
//关闭服务器端socket
s.close() ;
}
}
客户端发送数据,服务器端给客户端反馈数据...
public class ClientDemo {
public static void main(String[] args) throws IOException {
//创建客户端的Socket对象
Socket s = new Socket("192.168.10.101", 6666) ;
//获取通道内的输出流
OutputStream out = s.getOutputStream() ;
//将该数据发送到服务器端(通过通道内的流)
out.write("今天天气很好,没有雾霾".getBytes()) ;
//获取到服务器端反馈过来的数据
//获取通道内内的输入流对象
InputStream in = s.getInputStream() ;
//读数据
byte[] bys = new byte[1024] ;
int len = in.read(bys) ;//读取服务器端发送来的实际字节数(阻塞式)
//显示服务器端反馈的数据
String client = new String(bys, 0, len) ;
System.out.println("clinet:"+client);
//释放资源
s.close() ;
}
}
public class ServerDemo {
public static void main(String[] args) throws IOException {
//1)创建服务器端Socket对象
ServerSocket ss = new ServerSocket(6666) ;
System.out.println("正在等待客户端连接...");
//2)监听客户端的连接
Socket s = ss.accept() ;//阻塞式方法结束,连接了(侦听到客户端的和的服务器端端口一致)
System.out.println("客户端已连接...");
//3)服务器端获取通道内输入流对象
InputStream in = s.getInputStream() ;
//客户端发送端数据显示控制台
byte[] bys = new byte[1024] ;
int len = in.read(bys) ;//阻塞式
String server = new String(bys, 0, len) ;
//输出客户端给服务器端发送的数据
System.out.println("server:"+server);
//服务器反馈
//获取通道内的输出流
OutputStream out = s.getOutputStream() ;
//给客户端反馈数据
out.write("我已收到,谢谢".getBytes()) ;
//关闭资源
s.close() ;//关闭掉侦听的客户端所在的通道内的对象(Socket)
// ss.close() ;
}
}
需求:客户端键盘录入数据,服务器端将数据显示控制台
public class ClientDemo {
public static void main(String[] args) throws IOException {
//1)创建客户端socket对象
Socket s = new Socket("192.168.10.101", 2222) ;
//2)数据是键盘录入(IO流的形式)
//BufferedReader字符流封装数据,读取键盘录入的数据
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;
//3)客户端要发送数据,获取通道内的流,getOutputStream() :字节输出流
//使用字符缓冲输出流封装通道内的流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
s.getOutputStream()));
//利用BufferedReader一次读取一行数据:readLine
//BuffereWriter将键盘录入的数据(写到通道内的流中)以流的形式发送端服务器端: newLine() ,flush()
String line = null ;
while((line=br.readLine())!=null){
//键盘录入一行数据,就把一行数据写入到被封装的通道内的流中
//什么时候结束
//自定义结束条件
if("over".equals(line)){
break ;
}
bw.write(line) ;
bw.newLine() ;
bw.flush() ;
}
//关闭资源
s.close() ;
}
}
服务器端将客户端键盘录入的数据读取出来显示控制台
public class ServerDemo {
public static void main(String[] args) throws IOException {
//1)创建服务器端的Socket对象
ServerSocket ss = new ServerSocket(2222) ;
System.out.println("等待客户端连接...");
//2)监听客户端的连接
Socket s = ss.accept() ;
System.out.println("客户端已经连接了...");
//3)封装服务器通道内的流
BufferedReader br = new BufferedReader(new InputStreamReader(
s.getInputStream()));
//一次读取一行数据
String line = null ;
while((line=br.readLine())!=null){
//输出数据
System.out.println(line);
}
//关闭资源
//ss.close() ;//服务器端 不需要关闭
s.close() ;
// br.close() ;
}
}
客户端键盘录入,服务器输出将录入的内容输出到文本文件
public class ClientDemo {
public static void main(String[] args) throws IOException {
//创建客户端的Socket对象
Socket s = new Socket("192.168.10.101", 3456) ;
//键盘录入:IO流的形式
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//封装通道内的流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
s.getOutputStream()));
//一次读取一行数据
String line = null ;
while((line=br.readLine())!=null){
//自定义结束标记
if("over".equals(line)){
break ;
}
//将录入的数据写入到被封装的通道内的流中
bw.write(line) ;
bw.newLine() ;
bw.flush() ;
}
//释放资源
s.close() ;
}
}
public class ServerDemo {
public static void main(String[] args) throws IOException {
//1)创建服务器端的Socket对象
ServerSocket ss = new ServerSocket(3456) ;
//2)监听客户端连接
Socket s = ss.accept() ;
//3)封装通道内的流
BufferedReader br = new BufferedReader(new InputStreamReader(
s.getInputStream()));
//4)服务器端输出一个文本文件
BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt")) ;
//服务器端通道内的流读取客户端发送的数据,将数据一次写入到a.txt文件中
String line = null ;
while((line=br.readLine())!=null){
//写入到文本文件中
bw.write(line) ;
bw.newLine() ;
bw.flush() ;
}
//关闭资源
s.close() ;
bw.close() ;
}
}
public class ClientDemo {
public static void main(String[] args) throws IOException {
//1)创建客户端的Socket对象
Socket s = new Socket("192.168.10.101", 4567) ;
//2)要封装文本文件:
BufferedReader br = new BufferedReader(new FileReader(
"InetAddressDemo.java"));
//3)封装通道内的流:将字节输出流封装成字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
s.getOutputStream()));
//4)需要将文本文件中的数据(内容)写入到被封装的通道内的流中
String line = null ;
while((line=br.readLine())!=null){
//读取一行,将数据写一行到通道流中
bw.write(line) ;
bw.newLine() ;
bw.flush() ;
}
//释放资源
br.close() ;
s.close() ;
}
}
public class ServerDemo {
public static void main(String[] args) throws IOException {
//创建服务器端是Socket对象
ServerSocket ss = new ServerSocket(4567) ;
//监听客户端
Socket s = ss.accept() ;
//封装通道内的流
BufferedReader br = new BufferedReader(new InputStreamReader(
s.getInputStream()));
//读取一行数据,就展示到控制台上
String line = null ;
while((line=br.readLine())!=null){
//展示控制台
System.out.println(line);
}
//释放资源
s.close() ;
}
}
客户端文本文件,服务器端将文本文件中的内容复制输出到一个新的文本文件中,
并且服务器端反馈给客户端,文件复制成功了...
按照正常的罗操作写完了客户端和服务器的需求,运行的时候,发现都处于等待情况,是什么原因呢?
对于客户端来说,它要将java文件写入到字符输出流中(通道内的流),在最终返回如果是null(null在网络编程中是不能作为结束条件的)的情况下,文件读完了,但是服务器端不指定
客户端这边java文件是否读完了,两端readLine都处于阻塞,如何解决?
方案1:在客户端这边定义结束标记,服务器端只要读到结束标记了,就表示读完了.
该方式虽然可以,但是可能文件中有某句话就是自定义结束语句,可能文件压根没有读完就结束了!,不够好!
方案2:public void shutdownOutput() throws IOException禁用此套接字的输出流
public class UploadClient {
public static void main(String[] args) throws IOException {
//1)创建客户端的Socket对象
Socket s = new Socket("192.168.10.101", 6666) ;
//2)封装文本文件,对于文本文件字符缓冲输入流
BufferedReader br = new BufferedReader(
new FileReader("SellTicket.java"));
//3)封装通道内字节输出流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
s.getOutputStream()));
//将SellTicket.java文件中的内容一次读取一行写入到通道内的流中
String line = null ;
while((line=br.readLine())!=null){ //阻塞
//
bw.write(line) ;
bw.newLine() ;
bw.flush() ;
}
//方式1
//定义一个结束标记
// bw.write("over") ;
// bw.newLine() ;
// bw.flush() ;
//通过这个方法告诉服务器端,客户端这边没数据了,读完了,你反馈
s.shutdownOutput() ;//(推荐使用这种方式)
//读取服务器端的反馈
//获取通道内的输入流对象
BufferedReader brClinet = new BufferedReader(new InputStreamReader(
s.getInputStream()));
//读数据
String fk = brClinet.readLine() ;
System.out.println(fk);
//释放资源
br.close() ;
s.close() ;
}
}
public class UploadServer {
public static void main(String[] args) throws IOException {
//创建服务器端的socket对象
ServerSocket ss = new ServerSocket(6666) ;
//监听客户端连接
Socket s = ss.accept() ;
//封装通道内的流
BufferedReader br = new BufferedReader(new InputStreamReader(
s.getInputStream()));
//服务器端要将输出文本文件进行复制
BufferedWriter bw = new BufferedWriter(new FileWriter("copy.java")) ;
String line = null ;
while((line=br.readLine())!=null){ //读到的null的情况,文件读完毕 ,阻塞
//读到什么结束
// if(("over").equals(line)){
// break ;
// }
bw.write(line) ;
bw.newLine() ;
bw.flush();
}
/**
* 服务器端反馈
*/
//获取通道内的输出流对象,并且用BufferedWrite封装
BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(
s.getOutputStream()));
bwServer.write("文件复制完了...") ;
bwServer.newLine() ;
bwServer.flush() ;
//关闭资源
bw.close() ;
s.close() ;
}
}
客户端的图片文件,服务器端输出一个图片文件并且给出反馈
public class UploadClient {
public static void main(String[] args) throws IOException {
//创建客户端的socket对象
Socket s = new Socket("192.168.10.101", 8888) ;
//先封装文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("林青霞.jpg")) ;
//获取通道内的流 输出流 OutputStream
BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream()) ;
//一次读取一个字节数组
byte[] bys = new byte[1024] ;
int len = 0 ;
while((len=bis.read(bys))!=-1){
//读个字节写到输出流中
bos.write(bys, 0, len) ;
//刷新
bos.flush() ;
}
//客户端需要给服务器提供一个终止,告诉服务器端我没有数据了
s.shutdownOutput() ;
//客户端读取服务器的反馈
InputStream is = s.getInputStream() ;
byte[] bys2 = new byte[1024] ;
int len2 = is.read(bys2) ;
System.out.println(new String(bys2,0,len2));
//关闭资源
bis.close() ;
s.close() ;
}
}
public class UploadServer {
public static void main(String[] args) throws IOException {
//服务器端
//获取socket对象
ServerSocket ss = new ServerSocket(8888) ;
//监听
Socket s = ss.accept() ;
//封装通道内的流
BufferedInputStream bis = new BufferedInputStream(s.getInputStream()) ;
//输出图片文件
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("mm.jpg"));
//一次读取一个字节数组
byte[] bys = new byte[1024] ;
int len = 0 ;
while((len=bis.read(bys))!=-1){
bos.write(bys, 0, len) ;
//刷新字节缓冲输出流
bos.flush() ;
}
//服务器端给客户端反馈
OutputStream out = s.getOutputStream() ;
out.write("文件上传成功".getBytes()) ;
//释放资源
bos.close() ;
s.close() ;
}
}