`
fancaiwen
  • 浏览: 3711 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

通信之文件传输

 
阅读更多

        我们要通信就必须要有一个服务器和多个客户端,如同打电话时的被叫与主叫,而实现二者的连接就必    须有一套规则,即通信协议。

   

    今天说的就是自定义通信协议来实现文件的传输。

     

    首先我们说一下消息传输时服务器读取消息的规则:

       1.读取消息的总长,int型数据

       2.读取消息的类型,byte型数据,1为文本聊天消息,2为文件

       3.若类型为1时,则再读取接收者的号码(int型数据),消息内容

       4.若类型为2时,则读取消息的规则为:读取接收者的号码,读取文件名,读取文件内容,保存文件

    

    具体代码:

       服务器:

    

import java.io.DataInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Sever {
	//启动主函数
    public static void main(String[] args) {
    	Sever cs = new Sever();
        cs.setUpServer(1111);
    }
    /**
    * 在指定端口上启动一个服务器
    * @param port:服务器所用的端口
    */
    public void setUpServer(int port) {
    	try {
    		// 1.建立绑定在指定端口上的服务器对象
                ServerSocket server = new ServerSocket(port);
            
                while (true) { 
            	// 让服务器进处循环等待状态
                Socket client = server.accept();
                System.out.println("Incoming clieng:"+client.getRemoteSocketAddress());
                // 调用处理连接对象的方法去处理连接
                processChat(client);
            }
          } catch (Exception ef) {
        	  ef.printStackTrace();
           }
    }
     // 处理客户机进入的连接对象
     private void processChat(java.net.Socket client) {
        	try {
        		// 得到一个输出/输入流对象
                        OutputStream out = client.getOutputStream();
                         InputStream ins = client.getInputStream();
                        //将输入流包装为DataInputStream方便读取原始类型的流
                        DataInputStream dins=new DataInputStream(ins);
                while(true){
                	//开始读取数据:每一条消息,总是以一个int开头
                    //1.读消息长度,readInt()方法底层从流中读取4个字节,组成一个int
                    int totalLen=dins.readInt();
                    System.out.println("*******进入一条消息总长: "+totalLen);
                    //2.读取消息类型标识,只读取一个字节
                    byte flag=dins.readByte();
                    System.out.println("消息接收类型为: "+flag);
                    //3.读取目标客户号码,一个int
                    int destNum=dins.readInt(); //消息头解析完毕
                    System.out.println("消息接收目标用户号是: "+destNum);
                    //根据消息的类型,读取消息体部分
                    if(flag==1){
                    	//类型为1,是文本聊天消息,按其规则读取
                        //创建对应消息体部分字节的长度的数据
                        byte[] data=new byte[totalLen-4-1-4];

                        //从流中读取data.length个字节放入数组中
                        dins.readFully(data);
                        String msg=new String(data);//转成字符串
                        System.out.println("发给文本给:"+destNum+" 内容是:"+msg);
                    }
                   else if(flag==2){
                	   //文件数据包体解析
                       System.out.println("发送文件给:"+destNum);
                       byte[] data=new byte[256];
                       dins.readFully(data);//读取256个字节做文件名字
                       //解析出了文件名字,并去除末尾空格
                       String fileName=new String(data).trim();
                       System.out.println("读到的文件名字是: "+fileName);
                       //余下的字节就是文件内容
                       data=new byte[totalLen-4-1-4-256];//文件字节数据总长
                       dins.readFully(data);//读入文件的字节
                       //保存文件到当前目录下:
                       FileOutputStream fous=new FileOutputStream(fileName);
                       fous.write(data);
                       fous.flush();
                       fous.close();
                       System.out.println("文件保存完成!");
                    }else{
                    	System.out.println("收到未知数据包: "+flag);
                        client.close();
                    }
                }
             } catch (Exception ef) {
            	 ef.printStackTrace();
            }
        }
 }

    注意:

     1.将InputStream包装为DataInputStream流对象:

            可以将Socket上得到的输入流包装为DataInputStream流对象,随后,如果调用dins的readByte()               时,只会从底层的数据流中读取一个字节返回;而调用readInt()时,则从底层读取4个字节(32位),             readInt() 方法内部经过位运算实现了将读到的4个字节组成一个int型数据返回

     2.read()方法与readFully()方法的区别:

         当发送大数据量时,有可能一部分数据已发送到对方,有一部分数据还在本地的网卡缓存中,如果调

    用read()方法 可能会提前返回而没有读到足够的数据,在传大块数据(如一次传送一个较大文件时)可

    能出错,而readfully()方法一直等待,读取到数组长度的所有数据,才会返回。

      
     客户端 :

      客户端代码要发送数据时,也必须按照协议格式和顺序将组成消息的各部分数据发送。发送据时应用到      DataOutputStream对象,调用其writeInt(1)方法时,这个整数1会被作为4个字节写入到流中;但如果调用      writeByte(1)方法写入,就只会写入一个字节。

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Scanner;


public class Chat {
    private DataOutputStream dous;//输出流对象
    
    private void writeString(DataOutputStream out,String str,int len){
    	try{
    		byte[] data=str.getBytes();
                out.write(data);
                //假设都是短,需要补0
                while(len>data.length){
            	    out.writeByte('\0');
                    len--;
                }
         }catch(Exception ef){
        	 ef.printStackTrace(); 
         }
    }
    /**
    * 发送一条文本消息
    * @param msg:消息内容
    * @param destNum:接收者号码
    */
    private void sendTextMsg(String msg,int destNum){
    	try{
    		byte[] strb=msg.getBytes();//得到消息的字节数
                int totalLen=4+1+4+strb.length;
                System.out.println("发送总长度为: "+totalLen);
                dous.writeInt(totalLen); //总长
                dous.writeByte(1); //类型:1为文本消息
                dous.writeInt(destNum);//写入目标用户号
                dous.write(strb);//写入消息内容
                dous.flush();
        }catch(Exception ef){ 
        	ef.printStackTrace();
        }
    }
    /**
    * 发送一个文件数据包
    * @param fileName:文件绝对路径名
    * @param destNum:目标用户号码
    */
    private void sendFileMsg(String fileName,int destNum){
    	try{
    		//根据文件名创建文件对象
                File file=new File(fileName);
                //根据文件对象,构造一个输入流
                InputStream ins=new FileInputStream(file);
                int fileDataLen=ins.available();//文件数据总长
                int totalLen=4+1+4+256+fileDataLen; //得到了要发送数据包的总长
                dous.writeInt(totalLen);
                dous.writeByte(2);//类型是2,即文件数据包
                //写入目标用户号
                dous.writeInt(destNum);
                //文件名
                String shortFileName=file.getName();
               //写入文件名,不足256个长度时,补\0
               writeString(dous,shortFileName,256);
               byte[] fileData=new byte[fileDataLen];
               ins.read(fileData);//读入文件数据
               dous.write(fileData);//写出到服务器的流中
               dous.flush(); //
         }catch(Exception ef){ 
        	 ef.printStackTrace(); 
        }
    }
    /**
    * 连接上服务器
    * @param ip:服务器ip
    * @param port:服务器端口
    */
    public void conn2Server(String ip, int port) {
    	 // 创建一个到服务器端的Socket对象
         try {
        	 java.net.Socket client = new java.net.Socket(ip, port);
                 // 得到输入输出流对象
                 InputStream ins = client.getInputStream();
                 OutputStream ous = client.getOutputStream();
                //将输出流包装为DataOutputStream对象
                int testCount=0;
             while(true){
                 dous=new DataOutputStream(ous);

            	 System.out.println("登录服务器成功,请选择你要发的类型(1:聊天 2:文件:");
              
                 Scanner sc=new Scanner(System.in);
                 int type=sc.nextInt();
                 if(type==1){
                     sendTextMsg("abc聊天内容"+testCount,1111);
                 }
                 if(type==2){
                     //发文件,注这个文件必须存在
                     sendFileMsg("G:\\l.txt",1111);
                 }
                 testCount++;
              }
           } catch (Exception ef) {
        	   ef.printStackTrace();
        	}
         }
         //主函数:
         public static void main(String[] args) {
        	 Chat qqc = new Chat();
        	 qqc.conn2Server("127.0.0.1", 1111);
         }
}

      

 

 

     

0
0
分享到:
评论

相关推荐

    socket通信 文件传输等的功能

    在这个主题下,我们将深入探讨Socket通信的基本概念、工作原理以及如何应用于文件传输。 首先,Socket可以看作是网络上的端点,它允许应用程序通过网络发送和接收数据。在TCP/IP协议栈中,Socket分为两种类型:基于...

    socket通信文件传输

    以下是对Socket通信文件传输的详细解释: 1. **Socket基本概念**: Socket,也称为“套接字”,是网络通信中的一个抽象概念,它代表了两台机器之间的一个连接端点。在TCP/IP模型中,Socket接口提供了应用层与传输...

    用TCP/socket实现windows与linux通信(文件传输)

    本文件传输系统采用TCP协议进行通信,实现了windows与linux通信,打破了只能在windows下传输文件的弊端,本程序的编写对通信编程新手有很大的帮助作用,本系统目前只支持windows向linux发送多种类型文件,大文件传输...

    网络通信和文件传输简单示例程序(Win32)

    网络通信和文件传输简单示例程序。使用TCP进行文件传输,使用UDP进行网络文本通信。同时使用多线程监听消息。

    Qt编写的多线程局域网通信软件(含文件传输)

    《Qt技术深度解析:构建多线程局域网通信及文件传输软件》 在现代软件开发中,局域网通信和文件传输是不可或缺的一部分。本文将深入探讨如何使用Qt库,结合VS2010环境,实现基于TCP和UDP协议的多线程局域网通信软件...

    C#UDP通信+文件传输 源码

    本篇将详细介绍C#中基于UDP的通信及文件传输的相关知识点。 首先,UDP是一种无连接的、不可靠的传输协议,它不保证数据包的顺序、完整性和可靠性,但具有较低的延迟和较高的传输效率。在C#中,我们通常使用System...

    串口通信实现文件传输

    实现串口通信文件传输的第一步是建立连接。这通常涉及配置串口参数,如波特率、数据位等,并打开串口。在编程中,我们可以使用各种库来完成这个任务,如在Python中的pySerial库,C++的libserialport库等。 接着,...

    基于TCP的局域网多用户通信、文件传送程序详解.rar_tcp 通信_基于TCP-IP多线程文件传输_多用户_局域网文件_飞鸽传

    在IT领域,网络通信是核心部分之一,尤其是局域网内的多用户通信和文件传输。本文将深入探讨基于TCP协议的局域网多用户通信和文件传送程序,结合"飞鸽传书"这一实例,来解析相关技术要点。 首先,TCP(Transmission...

    局域网通信数据文件传输工具

    2. **断点续传**:如果文件传输过程中出现中断,工具应能保存已传输的部分,并在恢复时从断点处继续,减少因网络不稳定导致的重传。 3. **数据压缩**:在传输前对文件进行压缩,可以减少在网络中传输的数据量,...

    socket通信 QQ聊天 文件传输

    socket通信 QQ聊天 文件传输 socket通信 QQ聊天 文件传输 socket通信 QQ聊天 文件传输

    C#UDP通信+文件传输

    总的来说,要改进"C# UDP通信+文件传输"的应用,开发者需要在接收到文件数据后提供一个用户界面,让用户选择保存文件的路径,同时考虑在网络通信中添加额外的错误恢复策略,以提高文件传输的可靠性。这是一个涉及到...

    QT学习之文件传输和断点续传

    在这个"QT学习之文件传输和断点续传"的主题中,我们将深入探讨如何在QT环境中实现基于TCP的文件传输功能,并且特别关注断点续传技术。 首先,让我们了解TCP(Transmission Control Protocol)协议。TCP是一种面向...

    C# socket TCP 大文件传输同时实现断点续传

    在C#编程语言中,利用Socket API进行TCP通信可以构建高效、稳定的文件传输系统,特别是在处理大文件时,断点续传功能则显得尤为必要。下面,我们将深入探讨如何使用C#的Socket实现TCP大文件传输并支持断点续传。 ...

    C# TCP 通信(数据、文件的传输)

    总结来说,C#的TCP通信涉及客户端和服务端的建立连接、数据传输以及文件传输等核心步骤。开发者需要理解TCP协议的工作原理,并熟练运用C#提供的网络编程API,才能实现高效、稳定的网络通信系统。在实际项目中,还应...

    串口通信实现文件传输功能

    实现串口通信文件传输功能,采用API方式,实现串口通信文件传输功能

    visual c++ vc在电脑间传送大文件.支持同时多文件传输,断点续传,传送过程中可聊天IM及时通信.zip

    《使用Visual C++实现大文件传输与断点续传及即时通信系统》 在现代计算机技术中,文件传输是一项基础且重要的功能。特别是在局域网或互联网环境中,用户经常需要在不同的设备之间交换大量数据。Visual C++作为...

    基于linux下用c编写的socket通信传输文件的小程序

    服务器在发送文件时,可以设定合适的缓冲区大小,每次发送缓冲区中的数据,直到文件传输完毕。 7. 错误处理与调试: 网络编程中,错误处理至关重要,因为网络环境不稳定,可能出现各种异常情况。开发者需要对可能...

    socket通信,客户端向服务器传文件

    总结来说,Java中的Socket通信为客户端和服务器提供了双向通信的接口,可以用于文件传输。客户端通过建立Socket连接,读取文件内容并写入Socket的输出流,而服务器端则接收这些数据并保存到本地。这个过程涉及到了...

    利用vc++实现局域通信并传输文件

    在本文中,我们将深入探讨如何使用VC++通过MFC(Microsoft Foundation Classes)库来实现局域网内的通信以及文件传输。MFC是微软提供的一种C++类库,它封装了Windows API,使得开发者能更容易地创建Windows应用程序...

    Qt5.9实现TCP通信与文件传输

    在本文中,我们将深入探讨如何使用Qt5.9框架实现TCP通信和文件传输。Qt是一个跨平台的应用程序开发框架,广泛应用于GUI编程,同时也支持网络编程。以下将详细阐述相关知识点: 1. **TCP(Transmission Control ...

Global site tag (gtag.js) - Google Analytics