`

java学习笔记:TCP通讯,传送任意文件(服务端并发)

    博客分类:
  • java
阅读更多


 


 



 
 
 

 

 

/*
TCP通讯
需求:传送任意文件

tcp传输要定义2个端点,客户端和服务端
步骤
1.定义服务, 服务器ip和接收端口
2.读取客户端已有的图片文件
3.使用socket输出流将数据发给服务端
4.读取服务端的反馈信息
5.关闭资源

注意:
1.在while循环中的read方法最后读到文件结束标记-1后循环退出了
  而没有将该标记写入socket流中,那么服务端接收到的数据是不完整的,而且停不下来
  用shutdownOutput方法告诉服务端文件到了末尾结束发送了

[示例]:传送任意文件 (客户端)
*/

import java.net.*;
import java.io.*;
class Demo
{
  public static void main(String[] args) throws Exception
  {
    new FileClient("c:\\FoxitReader_CHS.rar"); //启动客户端,准备发送指定文件
  }
}

class FileClient  //客户端
{
  FileClient(String fileStr) throws Exception
  {
    s.op("客户端启动....");
    File file = new File(fileStr);  //关联一个文件c:\\FoxitReader_CHS.rar
    if(file.isFile())  //是一个标准文件吗?
    {
      client(file);    //启动连接
    }
    else
    {
      s.op("要发送的文件 "+fileStr+" 不是一个标准文件,请正确指定");
    }
  }
  
  public void client(File file)throws Exception
  {
    Socket sock= new Socket("192.168.1.3",10007); //指定服务端地址和端口

    FileInputStream fis = new FileInputStream(file); //读取本地文件
    OutputStream sockOut = sock.getOutputStream();   //定义socket输出流
    
    //先发送文件名.让服务端知道
    String fileName = file.getName();
    s.op("待发送文件:"+fileName);
    sockOut.write(fileName.getBytes());
    
    String serverInfo= servInfoBack(sock); //反馈的信息:服务端是否获取文件名并创建文件成功
    if(serverInfo.equals("FileSendNow"))   //服务端说已经准备接收文件,发吧
    {
      byte[] bufFile= new byte[1024];
      int len=0;
      while(true)
      {
        len=fis.read(bufFile);
        if(len!=-1)
        {
          sockOut.write(bufFile,0,len); //将从硬盘上读取的字节数据写入socket输出流
        }
        else
        {
          break;
        }
      }      
    }
    else
    {
      s.op("服务端返回信息:"+serverInfo);
    }
    sock.shutdownOutput();   //必须的,要告诉服务端该文件的数据已写完
    s.op("服务端最后一个返回信息:"+servInfoBack(sock));//显示服务端最后返回的信息
    
    fis.close();
    sock.close();
  }
  
  public String servInfoBack(Socket sock) throws Exception  //读取服务端的反馈信息
  {
    InputStream sockIn = sock.getInputStream(); //定义socket输入流
    byte[] bufIn =new byte[1024];
    int lenIn=sockIn.read(bufIn);            //将服务端返回的信息写入bufIn字节缓冲区
    String info=new String(bufIn,0,lenIn);
    return info;
  }
}

class s  
{
  public static void op(Object obj) //打印
  {
    System.out.println(obj);
  }
}

 

 

/*
服务端原先有很大的局限性
原先我们没有考虑客户端的文件名,和客户端判断是否有重名文件,我们是另外指定了文件名和路径
当客户端A连接服务端,被服务端获取到后,服务端执行具体流程,
这时如果B客户端尝试连接服务端,但只能等待
因为服务端还没有处理完A客户端的请求,不能回while起始位置执行accept方法,所以
暂时获取不到B客户端对象,那么为了可以让多个客户端同时被服务端并发接收,
那么服务端最好就是将每个客户端封装到一个个单独的线程中,这样,就可以同时处理多个客户端请求
如何定义线程呢?
只要明确每一个客户端要再服务端执行的代码即可,将该代码放到run方法中
如果服务端存在同名文件就返回信息并断开该次连接


如果要让客户端选择是否要覆盖文件,可以再加个反馈操作应该就可以了

[示例]:传送任意文件 (服务端并发执行)
*/
import java.net.*;
import java.io.*;
class Demo
{
  public static void main(String[] args) throws Exception
  {
    new FileServer();  //启动文件存储服务端
  }
}

class FileServer  //服务端
{
  FileServer() throws Exception
  { 
    s.op("服务端启动......");
    server();
  }

  public void server() throws Exception
  {
    ServerSocket serversock = new ServerSocket(10007);  //监听端口
    while(true)
    {   
      Socket sock = serversock.accept();            //循环等待客户端连接
      new Thread(new FileServThread(sock)).start(); //当成功连接客户端后开启新线程接收文件
    }
  }
}

class FileServThread implements Runnable   //服务端线程
{
  private Socket sock;
  FileServThread(Socket sock)
  {
    this.sock = sock;
  }
  
  public void run()
  {
    String ip = sock.getInetAddress().getHostAddress();   //获取客户端ip
    try
    {
      s.op("开启新线程接收来自客户端IP: "+ip+" 的文件");
      InputStream sockIn= sock.getInputStream();//定义socket输入流,接收客户端的信息
      File file =getClientFileName(sockIn);     //创建同名文件
      if(file==null)
      {
        writeOutInfo(sock,"存在同名文件或获取文件失败,服务端断开连接!");
        sock.close();              return;
      }
     
      FileOutputStream fos= new FileOutputStream(file); //用来写入硬盘
      byte[] bufFile = new byte[1024*1024];   //接收数据的缓存
      int len=0;
      while(true)
      {
        len=sockIn.read(bufFile); //接收数据
        if(len!=-1)
        {
          fos.write(bufFile,0,len); //写入硬盘文件
        }
        else
        {
          break;
        }
      }
      writeOutInfo(sock,"上传成功!");   //文件接收成功后给客户端反馈一个信息
      s.op("文件接收成功!"+System.getProperty("line.separator"));  //服务端打印一下
      fos.close();
      sock.close();     
    }
    catch(Exception ex)
    {
      throw new RuntimeException(ip+"异常!!!");
    }
  }
  
  public void writeOutInfo(Socket sock,String infoStr)throws Exception//将信息反馈给服务端
  {
    OutputStream sockOut = sock.getOutputStream();
    sockOut.write(infoStr.getBytes());
  }
  
  public File getClientFileName(InputStream sockIn) throws Exception //获取文件名并创建
  {  
    //获取客户端请求发送的文件名,并判断在D盘创建同名文件的情况
    byte[] bufName=new byte[1024];
    int lenInfo =0;
    lenInfo = sockIn.read(bufName);  //获取文件名
    String fileName = new String(bufName,0,lenInfo);
    
    File dir = new File("d:\\");    //存到D盘根目录
    File[] files=dir.listFiles();   //遍历d盘目录
    for(File f:files)
    {
      if(!f.isDirectory())  //如果遍历到的该文件不是一个目录的话
      { 
        if(f.getName().equals(fileName))  //判断是否是同名文件
        {
          s.op(f.getName()+"文件已存在,断开该ip连接."+System.getProperty("line.separator"));
          writeOutInfo(sock,"服务端已存在同名文件!"); //反馈给客户端的信息
          return null;       
        }
      }
    }
    s.op("将客户端发来的文件( "+fileName+" )存到"+dir.getAbsolutePath());     
    File file= new File(dir+fileName);  
    if(file.createNewFile())
    { 
      s.op("成功创建文件("+fileName+" )准备写入数据");
      writeOutInfo(sock,"FileSendNow");    //告诉客户端,开始传送数据吧  
      return file;
    }
    else
    {
      return null; //如果由于硬盘满了等原因创建文件失败的话
    }
  }
}

class s
{
  public static void op(Object obj) //打印
  {
    System.out.println(obj);
  }
}

 

  • 大小: 40.2 KB
  • 大小: 66 KB
  • 大小: 82.3 KB
2
0
分享到:
评论
2 楼 xouou_53320 2015-12-17  
lastSeries 写道
前辈,是不是在工作以后连System.out.println()这样的函数也得用一个类封装呀,是不是得从现在就养成这样的习惯

其实是我比较懒
1 楼 lastSeries 2015-11-23  
前辈,是不是在工作以后连System.out.println()这样的函数也得用一个类封装呀,是不是得从现在就养成这样的习惯

相关推荐

    JAVA学习笔记 林信良

    《JAVA学习笔记》是林信良先生的一部深入浅出的Java编程教程,旨在帮助初学者和有一定经验的开发者巩固和提升Java编程技能。这本书涵盖了Java语言的基础到高级概念,是一份宝贵的自学资料。 首先,从基础部分开始,...

    java学习笔记

    网络编程也是Java的一大亮点,Java学习笔记会介绍Socket编程,使读者能够创建基于TCP/IP的客户端和服务端应用程序。此外,还会涉及多线程编程,这是并发处理和提高程序性能的关键技术,包括线程的创建、同步和通信。...

    java学习笔记之大鹏JAVA终级总结

    Java学习笔记之大鹏JAVA终级总结,是针对Java编程语言深入学习和面试准备的一份综合资料。这份总结涵盖了从基础知识到高级概念的多个方面,旨在帮助初学者理解和掌握Java的核心概念,同时解决面试中可能出现的关键...

    java学习笔记基础和框架

    Java学习笔记基础与框架 Java是一种广泛使用的面向对象的编程语言,它的设计目标是具有简单性、面向对象、健壮性、安全性、可移植性等特点。这份“java学习笔记基础和框架”涵盖了从Java的基础概念到高级特性的全...

    Java 基础 第3阶段:高级应用-尚硅谷学习笔记(含面试题) 2023年

    在这个阶段的学习中,尚硅谷提供了2023年的学习笔记和面试题,帮助你提升Java技能并为求职做好准备。 首先,多线程是Java的一个关键特性,允许程序同时执行多个任务。理解线程的创建(通过Thread类或实现Runnable...

    在工作中java学习资料学习笔记

    6. **网络编程**:Java提供Socket编程接口,可以用于创建客户端和服务端应用程序。理解TCP和UDP协议,以及如何使用Java实现网络通信。 7. **异常处理**:Java的异常处理机制通过try-catch-finally语句块来捕获和...

    java学习资料 学习笔记

    根据提供的文件信息,标题为“java学习资料 学习笔记”,描述部分虽然重复了“学习资料”这个词,但我们可以理解这份材料是关于Java编程语言的学习资料。由于描述和标签部分的信息较为有限,我们将依据这些关键词...

    java基础知识学习笔记

    这篇“java基础知识学习笔记”是为初学者设计的,涵盖了从入门到精通的关键概念,旨在帮助新手快速掌握Java编程。 首先,从入门阶段开始,Java的学习会从安装JDK(Java Development Kit)开始,这是编写、编译和...

    Java-J2SE学习笔记

    这份"Java-J2SE学习笔记"涵盖了Java编程语言的基础到高级特性,是深入理解Java编程的重要参考资料。以下是对笔记中可能包含的关键知识点的详细解释: 1. **Java语言基础**: - **数据类型**:包括基本类型(如int...

    Java_notes:个人Java学习笔记

    11. **网络编程**:Java的Socket和ServerSocket类提供了TCP/IP网络通信的能力,可用于构建客户端和服务端应用程序。 12. **反射**:Java反射机制允许在运行时动态地获取类的信息(如类名、方法名)并调用方法,增强...

    JAVA源码笔记

    这份"JAVA源码笔记"集合了作者从零开始学习Java时,通过观看网络视频并结合实践所整理的一系列源码和学习心得。这不仅有助于加深对Java语言的理解,也能帮助初学者建立良好的编程思维。 首先,我们要明白Java是一种...

    JAVA核心知识点整理.zip

    7. **网络编程**:Java的Socket编程允许创建客户端和服务端应用,理解TCP和UDP协议,以及Socket和ServerSocket类的使用,是进行网络通信的基础。 8. **反射机制**:Java反射机制允许在运行时检查类、接口、字段和...

    Javaq备战秋招面试题-重点学习笔记.zip

    这份"Javaq备战秋招面试题-重点学习笔记.zip"文件包含了面试必备的Java知识点,帮助你全面复习并提升技能。 1. **基础语法**:理解并掌握Java的基础语法是所有Java程序员的起点,包括变量、数据类型(基本类型和...

    【Socket编程】--TCP异步通讯一服务器多客户端

    在TCP异步通讯中,服务器并不直接等待每一个客户端的响应,而是采用非阻塞的方式处理多个客户端请求,这样可以提高服务端的并发处理能力,优化系统资源的利用。 首先,让我们来了解TCP服务器的基本构建。一个TCP...

    JAVA试题 JAVA复习题 JAVA复习笔记

    本压缩包集合了多种JAVA试题与复习笔记,涵盖了基础理论、编程实践以及解题技巧等多个方面,旨在帮助Java学习者巩固知识,提升编程能力。 1. **Java基础** - **数据类型**:包括基本数据类型(如int、char、...

    魔乐java培训课堂笔记.7z

    9. **网络编程**:Java的Socket编程用于实现客户端和服务端的通信,理解TCP和UDP协议的区别,以及ServerSocket和Socket类的使用。 10. **JVM原理**:了解Java虚拟机的工作原理,包括类加载机制、内存管理(堆、栈、...

    Java预科总结笔记.rar

    7. **网络套接字**:Java的Socket类和ServerSocket类提供了网络通信的能力,理解TCP和UDP协议的区别,以及如何创建客户端和服务端套接字进行数据交换。 8. **单例模式**:单例模式是一种设计模式,确保一个类只有一...

    MIna2.0学习笔记

    Apache Mina是一个高性能、异步事件驱动的网络应用程序框架,主要用在开发网络通信应用,如TCP/IP和UDP协议的应用。Mina2.0作为其更新版本,提供了更丰富的功能和优化的性能,使得开发者能更高效地构建网络服务。 *...

    Go 学习笔记 第六版 下卷 - 预览.pdf

    不过,考虑到文件标题为《Go 学习笔记 第六版 下卷 - 预览.pdf》,我可以根据这个标题推测文件中可能包含的关于Go语言的知识点,并尝试详细说明这些内容。 Go语言,通常被称作Golang,是由Google设计并开发的一种...

Global site tag (gtag.js) - Google Analytics