我们要通信就必须要有一个服务器和多个客户端,如同打电话时的被叫与主叫,而实现二者的连接就必 须有一套规则,即通信协议。
今天说的就是自定义通信协议来实现文件的传输。
首先我们说一下消息传输时服务器读取消息的规则:
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); } }
相关推荐
在这个主题下,我们将深入探讨Socket通信的基本概念、工作原理以及如何应用于文件传输。 首先,Socket可以看作是网络上的端点,它允许应用程序通过网络发送和接收数据。在TCP/IP协议栈中,Socket分为两种类型:基于...
以下是对Socket通信文件传输的详细解释: 1. **Socket基本概念**: Socket,也称为“套接字”,是网络通信中的一个抽象概念,它代表了两台机器之间的一个连接端点。在TCP/IP模型中,Socket接口提供了应用层与传输...
本文件传输系统采用TCP协议进行通信,实现了windows与linux通信,打破了只能在windows下传输文件的弊端,本程序的编写对通信编程新手有很大的帮助作用,本系统目前只支持windows向linux发送多种类型文件,大文件传输...
网络通信和文件传输简单示例程序。使用TCP进行文件传输,使用UDP进行网络文本通信。同时使用多线程监听消息。
《Qt技术深度解析:构建多线程局域网通信及文件传输软件》 在现代软件开发中,局域网通信和文件传输是不可或缺的一部分。本文将深入探讨如何使用Qt库,结合VS2010环境,实现基于TCP和UDP协议的多线程局域网通信软件...
本篇将详细介绍C#中基于UDP的通信及文件传输的相关知识点。 首先,UDP是一种无连接的、不可靠的传输协议,它不保证数据包的顺序、完整性和可靠性,但具有较低的延迟和较高的传输效率。在C#中,我们通常使用System...
实现串口通信文件传输的第一步是建立连接。这通常涉及配置串口参数,如波特率、数据位等,并打开串口。在编程中,我们可以使用各种库来完成这个任务,如在Python中的pySerial库,C++的libserialport库等。 接着,...
在IT领域,网络通信是核心部分之一,尤其是局域网内的多用户通信和文件传输。本文将深入探讨基于TCP协议的局域网多用户通信和文件传送程序,结合"飞鸽传书"这一实例,来解析相关技术要点。 首先,TCP(Transmission...
2. **断点续传**:如果文件传输过程中出现中断,工具应能保存已传输的部分,并在恢复时从断点处继续,减少因网络不稳定导致的重传。 3. **数据压缩**:在传输前对文件进行压缩,可以减少在网络中传输的数据量,...
socket通信 QQ聊天 文件传输 socket通信 QQ聊天 文件传输 socket通信 QQ聊天 文件传输
总的来说,要改进"C# UDP通信+文件传输"的应用,开发者需要在接收到文件数据后提供一个用户界面,让用户选择保存文件的路径,同时考虑在网络通信中添加额外的错误恢复策略,以提高文件传输的可靠性。这是一个涉及到...
在这个"QT学习之文件传输和断点续传"的主题中,我们将深入探讨如何在QT环境中实现基于TCP的文件传输功能,并且特别关注断点续传技术。 首先,让我们了解TCP(Transmission Control Protocol)协议。TCP是一种面向...
在C#编程语言中,利用Socket API进行TCP通信可以构建高效、稳定的文件传输系统,特别是在处理大文件时,断点续传功能则显得尤为必要。下面,我们将深入探讨如何使用C#的Socket实现TCP大文件传输并支持断点续传。 ...
总结来说,C#的TCP通信涉及客户端和服务端的建立连接、数据传输以及文件传输等核心步骤。开发者需要理解TCP协议的工作原理,并熟练运用C#提供的网络编程API,才能实现高效、稳定的网络通信系统。在实际项目中,还应...
实现串口通信文件传输功能,采用API方式,实现串口通信文件传输功能
《使用Visual C++实现大文件传输与断点续传及即时通信系统》 在现代计算机技术中,文件传输是一项基础且重要的功能。特别是在局域网或互联网环境中,用户经常需要在不同的设备之间交换大量数据。Visual C++作为...
服务器在发送文件时,可以设定合适的缓冲区大小,每次发送缓冲区中的数据,直到文件传输完毕。 7. 错误处理与调试: 网络编程中,错误处理至关重要,因为网络环境不稳定,可能出现各种异常情况。开发者需要对可能...
总结来说,Java中的Socket通信为客户端和服务器提供了双向通信的接口,可以用于文件传输。客户端通过建立Socket连接,读取文件内容并写入Socket的输出流,而服务器端则接收这些数据并保存到本地。这个过程涉及到了...
在本文中,我们将深入探讨如何使用VC++通过MFC(Microsoft Foundation Classes)库来实现局域网内的通信以及文件传输。MFC是微软提供的一种C++类库,它封装了Windows API,使得开发者能更容易地创建Windows应用程序...
在本文中,我们将深入探讨如何使用Qt5.9框架实现TCP通信和文件传输。Qt是一个跨平台的应用程序开发框架,广泛应用于GUI编程,同时也支持网络编程。以下将详细阐述相关知识点: 1. **TCP(Transmission Control ...