TCP通信原理
TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象,从而在通信的两端形成虚拟网络链路。一旦建立了虚拟的网络链路,两端的程序就可以通过虚拟链路进行通信
TCP发送数据
发送数据步骤
- 创建客户端的Socket对象(Socket) Socket(String host,int port)
- 获取输出流,写数据
OutputStream getOutputStream() 释放资源 void close()
//创建客户端的Socket对象(Socket) //Socket(InetAddress address,int port)创建流套接字并将将其连接到指定IP地址的指定端口号 Socket s = new Socket(InetAddress.getByName("192.168.1.66"),,port:10000);//alt enter 抛出异常 //Socket(String host,int port)创建流套接字并将将其连接到指定IP地址的指定端口号 //和前面那个一样 只是第一个参数可以直接是字符串地址 Socket s = new Socket(host:"192.168.1.66",port:10000);//alt enter 抛出异常 //获取输出流,写数据 //OutputStream getOutputStream() 返回此套接字的输出流 OutputStream os = s.getOutputStream(); os.write(b:"hello,tcp,我来了".getBytes()) //释放资源 s.close();
TCP接收数据
接收数据步骤
- 创建服务器端的Socket对象(ServerSocket)
ServerSocket(int port) - 监听客户端连接,返回一个Socket对象 Socket accept()
- 获取输入流,读数据,并把数据显示在控制台 InputStream getInputStream()
释放资源 void close()
//创建服务器端的Socket对象(ServerSocket) //ServerSocket(int port)创建绑定到指定端口的服务器套接字 ServerSocket ss = new ServerSocket(port:10000);//alt enter 抛出异常 //Socket accept() 侦听要连接到此套接字并接受它 Socket s = ss.accept(); //获取输入流,读数据,并把数据显示在控制台 //InputStream getInputStream() 返回此套接字的输出流 InputStream is = s.getInputStream(); byte[] bys = new byte[1024]; int len = is.read(bys);//拿到的是实际发送了多少数据 String dataString = new String(bys,offset:0,len); sout("数据是:"+dataString); //释放资源 s.close(); ss.close();
TCP通信程序练习
练习1
- 客户端:发送数据,接收服务器反馈
服务器:接收数据,给出反馈
客户端程序//创建客户端的Socket对象(Socket) Socket s = new Socket(host:"192.168.1.66",port:10000);//alt enter 抛出异常 //获取输出流,写数据 OutputStream os = s.getOutputStream(); os.write(b:"hello,tcp,我来了".getBytes()) //接收服务器反馈 InputStream is = s.getInputStream(); byte[] bys = new byte[1024]; int len = is.read(bys);//拿到的是实际发送了多少数据 String data = new String(bys,offset:0,len); sout("客户端:"+data); //释放资源 s.close();
服务器端程序
//创建服务器端的Socket对象(ServerSocket) ServerSocket ss = new ServerSocket(port:10000);//alt enter 抛出异常 //监听客户端连接,返回一个Socket对象 Socket s = ss.accept(); //获取输入流,读数据,并把数据显示在控制台 InputStream is = s.getInputStream(); byte[] bys = new byte[1024]; int len = is.read(bys);//拿到的是实际发送了多少数据 String data = new String(bys,offset:0,len); sout("服务器:"+data ); //给出反馈 OutputStream os = s.getOutputStream(); os.write("数据已经收到".getBytes()); //释放资源 s.close(); ss.close();
练习2
- 客户端:数据来自于键盘录入,直到输入的数据是886,发送数据结束
服务器:接收到的数据在控制台输出
客户端程序//创建客户端的Socket对象(Socket) Socket s = new Socket(host:"192.168.1.66",port:10000);//alt enter 抛出异常 //数据来自于键盘录入,直到输入的数据是886,发送数据结束 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //封装输出流对象 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));//字节输出流转化成字符流,然后用BufferedWriter写数据封装 String line; while((line=br.readLine())!=null){//alt enter 抛出异常 //所输入的数据是886,发送数据结束 if("886".equals(line)){ break; } //如果不是,就获取输出流对象 //OutputStream os = s.getOutputStream(); //os.write(b:"hello,tcp,我来了".getBytes()); bw.write(line); bw.newLine(); bw.flush(); } //释放资源 s.close();
服务器端程序
//创建服务器端的Socket对象(ServerSocket) ServerSocket ss = new ServerSocket(port:10000);//alt enter 抛出异常 //监听客户端连接,返回一个对应的Socket对象 Socket s = ss.accept(); //获取输入流,读数据,并把数据显示在控制台 InputStream is = s.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); //上面三步合并为 BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));//输入流转化成字符流,再包装成BufferedReader String line; while((line=br.readLine())!=null){//alt enter 抛出异常 sout(line); } //释放资源 ss.close();
练习3
- 客户端:数据来自于键盘录入,直到输入的数据是886,发送数据结束
服务器:接收到的数据写入文本文件
客户端程序//创建客户端的Socket对象(Socket) Socket s = new Socket(host:"192.168.1.66",port:10000);//alt enter 抛出异常 //数据来自于键盘录入,直到输入的数据是886,发送数据结束 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //封装输出流对象 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));//字节输出流转化成字符流,然后用BufferedWriter写数据封装 String line; while((line=br.readLine())!=null){//alt enter 抛出异常 //所输入的数据是886,发送数据结束 if("886".equals(line)){ break; } //如果不是,就获取输出流对象 //OutputStream os = s.getOutputStream(); //os.write(b:"hello,tcp,我来了".getBytes()); bw.write(line); bw.newLine(); bw.flush(); } //释放资源 s.close();
服务器端程序
//创建服务器端的Socket对象(ServerSocket) ServerSocket ss = new ServerSocket(port:10000);//alt enter 抛出异常 //监听客户端连接,返回一个对应的Socket对象 Socket s = ss.accept(); //接收数据 BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));//输入流转化成字符流,再包装成BufferedReader //把数据写入文本文件 BufferedWriter bw = new BufferedWriter(new FileWriter(fileName:"myNet\\s.txt")); String line; while((line=br.readLine())!=null){//alt enter 抛出异常 bw.write(line); bw.newLine(); bw.flush(); } //释放资源 bw.close(); ss.close();
练习4
- 客户端:数据来自于文本文件
服务器:接收到的数据写入文本文件
客户端程序//创建客户端的Socket对象(Socket) Socket s = new Socket(host:"192.168.1.66",port:10000);//alt enter 抛出异常 //数据来自于文本文件 //封装文本文件的数据 BufferedReader br = new BufferedReader(new FileReader(fileName:"myNet\\InetAddressDemo.java")); //封装输出流写数据 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));//字节输出流转化成字符流,然后用BufferedWriter写数据封装 //读数据,并且把它写出去 String line; while((line=br.readLine())!=null){//alt enter 抛出异常 bw.write(line); bw.newLine(); bw.flush(); } //释放资源 br.close(); s.close();
服务器端程序
//创建服务器端的Socket对象(ServerSocket) ServerSocket ss = new ServerSocket(port:10000);//alt enter 抛出异常 //监听客户端连接,返回一个对应的Socket对象 Socket s = ss.accept(); //接收数据 BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));//输入流转化成字符流,再包装成BufferedReader //把数据写入文本文件 BufferedWriter bw = new BufferedWriter(new FileWriter(fileName:"myNet\\Copy.java")); String line; while((line=br.readLine())!=null){//alt enter 抛出异常 bw.write(line); bw.newLine(); bw.flush(); } //释放资源 bw.close(); ss.close();
练习5
- 客户端:数据来自于文本文件,接收服务器反馈
服务器:接收到的数据写入文本文件,给出反馈
- 出现问题:程序一直等待
- 原因:读数据的方法是阻塞式的
客户端程序
//创建客户端的Socket对象(Socket) Socket s = new Socket(host:"192.168.1.66",port:10000);//alt enter 抛出异常 //数据来自于文本文件 //封装文本文件的数据 BufferedReader br = new BufferedReader(new FileReader(fileName:"myNet\\InetAddressDemo.java")); //封装输出流写数据 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));//字节输出流转化成字符流,然后用BufferedWriter写数据封装 //读数据,并且把它写出去 String line; while((line=br.readLine())!=null){//alt enter 抛出异常 bw.write(line); bw.newLine(); bw.flush(); } //自定义结束标记 //bw.write(str:"886"); //bw.newLine(); //bw.flush(); //public void shutdownOutput() s.shutdownOutput(); //接收服务器的反馈 BufferedReader brClient = new BufferedReader(new InputStreamReader(s.getInputStream())); String data = brClient.readLine();//等待读取数据 sout("服务器的反馈:"+data); //释放资源 br.close(); s.close();
服务器端程序
//创建服务器端的Socket对象(ServerSocket) ServerSocket ss = new ServerSocket(port:10000);//alt enter 抛出异常 //监听客户端连接,返回一个对应的Socket对象 Socket s = ss.accept(); //接收数据 BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));//输入流转化成字符流,再包装成BufferedReader //把数据写入文本文件 BufferedWriter bw = new BufferedWriter(new FileWriter(fileName:"myNet\\Copy.java")); String line; while((line=br.readLine())!=null){//alt enter 抛出异常 还在这等着读数据呢 // if("886".equals(line)){ // break; // } bw.write(line); bw.newLine(); bw.flush(); } //给出反馈 BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); bwServer.write(str:"文件上传成功"); bwServer.newLine(); bwServer.flush(); //释放资源 bw.close(); ss.close();
练习6
- 客户端:数据来自于文本文件,接收服务器反馈
服务器:接收到的数据写入文本文件,给出反馈,代码用线程进行封装,为每一个客户端开启一个线程
客户端程序//创建客户端的Socket对象(Socket) Socket s = new Socket(host:"192.168.1.66",port:10000);//alt enter 抛出异常 //数据来自于文本文件 //封装文本文件的数据 BufferedReader br = new BufferedReader(new FileReader(fileName:"myNet\\InetAddressDemo.java")); //封装输出流写数据 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));//字节输出流转化成字符流,然后用BufferedWriter写数据封装 //读数据,并且把它写出去 String line; while((line=br.readLine())!=null){//alt enter 抛出异常 bw.write(line); bw.newLine(); bw.flush(); } //自定义结束标记 //bw.write(str:"886"); //bw.newLine(); //bw.flush(); //public void shutdownOutput() s.shutdownOutput(); //接收服务器的反馈 BufferedReader brClient = new BufferedReader(new InputStreamReader(s.getInputStream())); String data = brClient.readLine();//等待读取数据 sout("服务器的反馈:"+data); //释放资源 br.close(); s.close();
服务器端程序
//创建服务器端的Socket对象(ServerSocket) ServerSocket ss = new ServerSocket(port:10000);//alt enter 抛出异常 while(true){ //监听客户端连接,返回一个对应的Socket对象 Socket s = ss.accept(); //为每一个客户端开启一个线程 new Thread(new ServerThread(s)).start(); }
创建一个类实现线程
public class ServerThread implements Runnable{ private Socket s; public ServerThread (Socket s){ this.s = s; } //重写run方法 @Override public void run(){ //接收数据,写到文本文件 BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));//try catch捕获异常 //BufferedWriter bw = new BufferedWriter(new FileWriter(fileName:"myNet\\Copy.java")); //解决名称冲突问题 int count = 0; File file = new File(pathname:"myNet\\Copy["+count+"].java"); while(file.exists()){ count++; file = new File(pathname:"myNet\\Copy["+count+"].java"); } BufferedWriter bw = new BufferedWriter(new FileWriter(file)); String line; while((line=br.readLine())!=null){ bw.write(line); bw.newLine(); bw.flush(); } //给出反馈 BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); bwServer.write(str:"文件上传成功"); bwServer.newLine(); bwServer.flush(); //释放资源 s.close(); } }
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。