程序需求:客户端读取当前项目下的该图片文件,服务器端将文件的内容复制,输出一个新的图片文件:mm.jpg (服务器加上反馈)
TCP编程;(建立连接通道)
客户端的开发步骤:
1) 创建客户端的Socket对象
Socket s = new Socket(“ip”,端口) ;
Socket:就是客户端的Socket
构造方法
public Socket(InetAddress address, int port)
public Socket(String host, int port):创建客户端套接字对象,并且指定端口号和ip文本形式。
2) 获取该通道内的输出流对象
OutputStream out = s.getOutputStream();
-封装通道内的流:BufferedWriter
3) 写数据
out.write(“…”.getBytes()) ;
4) 释放资源
s.close() ;
客户端程序:
public static void main(String[] args) throws IOException {
//创建Socket对象 Socket("IP地址", 自定义端口号0~65535,其中0~1024不可用);
Socket s = new Socket("192.168.10.1", 19191);
//封装图片文件(因为传输文件,所以这里使用字节流传输故用BufferedInputStream)
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("风景.jpg")) ;
//封装通道的流
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);
//public void flush()
// throws IOException刷新此输出流并强制写出所有缓冲的输出字节
bos.flush();
}
//通知对方,数据已经完了
s.shutdownOutput();
//获取服务器端的反馈数据
//获取通道内的输入流对象
InputStream is = s.getInputStream() ;
byte[] buffer = new byte[1024] ;
int len2 = is.read(buffer) ;
String data = new String(buffer, 0, len2) ;
System.out.println(data);
//释放资源
s.close();
bis.close();
}
}
服务器端的开发步骤:
1) 创建服务器端的Socket对象,并且绑定某个端口号
ServerSocket ss = new ServerSocket(端口号) ;
2) 监听(阻塞式方法)
Socket s = ss.accept() ;
3) 获取通道内输入流对象
InputStream = s.getInputStream() ;
---àBufferedReader流对象
4) 一次读取一个字节数组的方式,输出数据(IO流读的操作)
服务器端程序:
public static void main(String[] args) throws IOException {
//创建Socket对象(在服务器端用ServerSocket(跟客户端一致的端口号))
ServerSocket ss = new ServerSocket(19191);
//监听客户端的连接(阻塞方法)public Socket accept():throws IOException侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞
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();
}
问题一:
程序运行抛出异常ava.net.BindException: Address already in use: JVM_Bind
异常原因:
地址被绑定,因为已经有服务器在监听客户端连接
问题二:
程序运行抛出异常java.net.ConnectException: Connection refused: connect 连接被拒绝
异常原因:
不要先运行客户端,客户端的连接需要服务器监听到才能连接,故得先运行服务器端程序,再运行客户端。
问题三:
客户端文本文件(使用字符缓冲流),服务器端复制该内容,并且输出一个新的文本文件,并且服务器给出反馈
使用缓冲流的时候,针对文本文件操作,客户端和服务器端通道内的流来说它不能用null作为信息的结束条件..
解决方案:
1) 客户端自定义结束条件,(往通道内输出流写一些结束条件),服务器端如果读到了该内容,就表示客户端的文本文件已经上传完毕,服务器端就开始反馈!(存在问题:如果文本文件中存在与结束条件相同的语句,那么文本未读完就会结束数据传输,因此尽量不要用自定义)
if("886".equals(line)) { //自定义结束条件
break ;
}
2) 直接在客户端的Socket对象中,通知服务器端反馈,并且客户端的文本文件已经读完客户端的数据,用public void shutdownOutput():通知服务器端(我没有数据了,你赶紧反馈)
语句形式为:Socket对象.shutdownOutput();此语句可通知对方数据已读完。