1)创建客户端的Socket对象
Socket:就是客户端的Socket
构造方法
public Socket(InetAddress address, int port)
public Socket(String host, int port):创建客户端套接字对象,并且指定端口号和ip文本形式
2)获取通道内的输出流对象
3)给服务器端写数据
4)释放资源
不要先运行客户端,客户端的连接需要服务器监听到才能连接,否则会出现异常:java.net.ConnectException: Connection refused: connect 连接被拒绝
服务端的开发步骤:
1)创建服务器端的Socket对象
2)监听客户端的连接(阻塞方法)
3)获取通道内的输入流
4)读取数据,显示控制台
5)释放资源
服务端不要运行多次,否则会出现异常:java.net.BindException: Address already in use: JVM_Bind 地址被绑定,因为已经有服务器在监听客户端连接
public class ClientDemo {
public static void main(String[] args) throws Exception {
//1)创建客户端的Socket对象
//public Socket(String host, int port)
Socket s = new Socket("192.168.10.1", 12306) ;
//2)获取通道内的输出流对象
// public OutputStream getOutputStream():获取套接字 的输出流
OutputStream out = s.getOutputStream() ;
//3)给服务器端写数据 过去
out.write("hello,Tcp,我来了".getBytes());
//释放资源
s.close();
}
}
public class ServerDemo {
public static void main(String[] args) throws Exception {
// 1)创建服务器端的Socket对象
// public ServerSocket(int port) throws IOException创建绑定到特定端口的服务器套接字
ServerSocket ss = new ServerSocket(12306);
// 2)监听客户端的连接(阻塞方法)
// public Socket accept(): throws IOException侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞
Socket s = ss.accept();
// 3)获取通道内的输入流
// InputStream getInputStream()
InputStream in = s.getInputStream();
// 4)读取数据,显示控制台
// 获取ip文本形式
// public InetAddress getInetAddress()
String ip = s.getInetAddress().getHostAddress();
byte[] bys = new byte[1024];
int len = in.read(bys);
String data = new String(bys, 0, len);
System.out.println("from" + ip + "data is :" + data);
// 5)释放资源
s.close();
// ss.close(); 服务端可以不关闭
}
}
需求:在刚才的基础上加入反馈,服务器端在接收到数据后向客户端发送反馈消息
public class ClientDemo {
public static void main(String[] args) throws IOException {
//创建客户端的Socket对象
Socket s = new Socket("192.168.10.1",10011) ;
//获取通道内的流,写数据
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(client);
//关闭资源
s.close();
}
}
public class ServerDemo {
public static void main(String[] args) throws IOException {
//创建服务器端的Socket对象
ServerSocket ss = new ServerSocket(10011);
//监听客户端连接
Socket s = ss.accept() ;
//服务器端获取通道内的输入流,读取数据
InputStream in = s.getInputStream() ;
byte[] bys =new byte[1024] ;
int len = in.read(bys) ;
System.out.println(new String(bys, 0, len));
//服务器端给客户端反馈
//获取通道内的输出流
OutputStream out = s.getOutputStream() ;
out.write("数据已经收到".getBytes());
//服务器端不需要关闭
s.close();
}
}
需求:客户端键盘录入数据 ,服务器端将数据输出在控制台上
public class ClientDemo {
public static void main(String[] args) throws IOException {
//创建客户端的Socket对象
Socket s = new Socket("192.168.10.1", 22222) ;
//使用字符缓冲输入流的录入方式
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;
//封装通道的流(s.getOutputStream())
BufferedWriter bw =
new BufferedWriter(new OutputStreamWriter(s.getOutputStream())) ;
String line = null ;
while((line=br.readLine())!=null){
//自定义结束条件
if("886".equals(line)) { //xml解析技术
break ;
}
//录入完一条数据,使用通道内封装的流对象,写到服务器端去
bw.write(line);
bw.newLine();
bw.flush();
}
// 释放资源对象
// bw.close();
s.close();
// br.close(); 不断录入数据,不要关闭了
}
}
public class ServerDemo {
public static void main(String[] args) throws IOException {
//创建服务器端的Socket对象
ServerSocket ss = new ServerSocket(22222) ;
//监听客户端连接
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();
}
}
需求:客户端键盘录入,服务器输出文本文件
public class ClientTest {
public static void main(String[] args) throws IOException {
//有客户端Socket对象.指定ip和端口号
Socket s = new Socket("192.168.10.1", 23456) ;
//使用流的形式录入数据
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 ServerTest {
public static void main(String[] args) throws IOException {
//必须创建服务器端Socket
ServerSocket ss = new ServerSocket(23456) ;
//监听
Socket s = ss.accept() ;
//封装通道内的流
BufferedReader br =
new BufferedReader(
new InputStreamReader(s.getInputStream())) ;
//封装一个文本文件
BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt")) ;
String line = null ;
while((line=br.readLine())!=null) {
//边获取数据,并且同时将数据写到bw.txt文件中
bw.write(line);
bw.newLine();
bw.flush();
}
// 关闭资源
// br.close();
s.close();
bw.close();
}
}
需求:客户端读取文本文件,服务器端将数据输出在控制台上
public class ClientTest {
public static void main(String[] args) throws IOException {
//创建客户端的Socket
Socket s = new Socket("192.168.10.1", 12345) ;
//封装文本文件,使用字符缓冲输入流
BufferedReader br = new BufferedReader(
new FileReader("SendDemo.java")) ;
//封装通道的内流
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(s.getOutputStream())) ;
//读(读取当前项目下的文件)写(将数据写到通道内的流中)操作
String line = null ;
while((line=br.readLine())!=null) {
bw.write(line);
bw.newLine();
bw.flush();
}
//关闭
br.close();
s.close();
}
}
public class ServerTest {
public static void main(String[] args) throws IOException {
//创建Socket对象
ServerSocket ss = new ServerSocket(12345) ;
//监听
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();
}
}
需求:客户端读取当前项目下的某个文本文件,服务器复制这个文件内容输出一个新的文本文件(Copy.java)
public class UploadClient {
public static void main(String[] args) throws IOException {
//创建客户端的Socket对象
Socket s = new Socket("192.168.10.1",11111);
//封装文本文件
BufferedReader br = new BufferedReader(
new FileReader("SendDemo.java")) ;
//封装通道内的流
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(s.getOutputStream())) ;
//读写操作
String line =null;
while((line=br.readLine())!=null) {
bw.write(line);
bw.newLine();
bw.flush();
}
//释放资源
br.close();
s.close();
}
}
public class UploadClient {
public static void main(String[] args) throws IOException {
//创建客户端的Socket对象
Socket s = new Socket("192.168.10.1",11111);
//封装文本文件
BufferedReader br = new BufferedReader(
new FileReader("SendDemo.java")) ;
//封装通道内的流
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(s.getOutputStream())) ;
//读写操作
String line =null;
while((line=br.readLine())!=null) {
bw.write(line);
bw.newLine();
bw.flush();
}
//释放资源
br.close();
s.close();
}
}
按照正常的思路,加入了服务器端反馈操作,发现服务器端的反馈数据客户端并没有收到,客户端也没有结束一直处于阻塞状态,在等待服务器发送反馈数据,但文件的复制操作却已经完成!
在客户端这边,如果SendDemo.java读完了,服务器端那边并不知道是否读完(流是不能使用null作为信息结束条件的,但是客户端文本文件是可以用null作为信息结束条件的)
服务器等待客户端通知文本已经读完了,而客户端还需要服务器端反馈,两者相互等待。
解决方案:
1)客户端这边,写一个结束条件,---->服务器如果读取到了这个结束条件的话,服务器就可以反馈
第一种方式虽然可以解决问题,但不灵活!如:自定义的结束条件为“over”,但文本文件一开始的内容就是over,此时服务器以为读完了,但实际上并没有,因此在实际开发过程中经常使用第二种方式
2)public void shutdownOutput():通知服务器端(我没有数据了,你赶紧反馈)
public class UploadClient {
public static void main(String[] args) throws IOException {
//创建客户端的Socket对象
Socket s = new Socket("192.168.10.1",11111); //当前对象创建之后,就会和服务器端建立连接通道
//封装文本文件
BufferedReader br = new BufferedReader(
new FileReader("SendDemo.java")) ;
//封装通道内的流
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(s.getOutputStream())) ;
//读写操作
String line =null;
while((line=br.readLine())!=null) {
bw.write(line);
bw.newLine();
bw.flush();
}
//自定义的结束条件
/*bw.write("over");
bw.newLine();
bw.flush();*/
//通知服务器端,客户端的文件已经完了,赶紧给反馈
//public void shutdownOutput():
s.shutdownOutput();
//获取服务器反馈的数据
//获取通道内的字符输入流
BufferedReader brClient = new BufferedReader(
new InputStreamReader(s.getInputStream())) ;
String client = brClient.readLine() ;
System.out.println(client);
//释放资源
br.close();
s.close();
}
}
public class UploadServer {
public static void main(String[] args) throws IOException {
//服务器端的Socket对象
ServerSocket ss = new ServerSocket(11111) ;
//监听
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();
}
//服务端获取通道内的输出流对象
BufferedWriter bwServer = new BufferedWriter(
new OutputStreamWriter(s.getOutputStream())) ;
//向客户端反馈
bwServer.write("文件上传成功了");
bwServer.newLine();
bwServer.flush();
//释放资源
bw.close();
s.close();
}
}
需求:客户端读取当前项目下的图片文件,服务器端将文件的内容复制,输出一个新的图片文件:copy.jpg (服务器加上反馈)
public class UploadClient {
public static void main(String[] args) throws IOException {
//创建Socket对象
Socket s = new Socket("192.168.10.1", 19191);
//封装图片文件
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();
}
}
public class UploadServer {
public static void main(String[] args) throws IOException {
//创建Socket对象
ServerSocket ss = new ServerSocket(19191);
//监听
Socket s = ss.accept() ;
//封装通道内的流
BufferedInputStream bis = new BufferedInputStream(
s.getInputStream()) ;
//封装图片文件
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("copy.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();
}
}
注意:在图片的复制过程中,有可能会出现图片加载不全的情况,因此在写文件时一定要加上flush()方法来强制刷新。