TCP编程

TCP(建立连接通道)编程的客户端的开发步骤:
        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()方法来强制刷新。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值