客户端与服务器如何进行数据传输


感觉自己对于网络传输的问题一直很困惑。网上查阅的资料也不是自己想要的,所以只好到这里来求大神帮助!

最近在做聊天室,客户端是android,我自己在本地搭了workerman当做服务器。两边都是采用websocket协议。

我用inputstream读取txt文件通过websocket发送到服务器,服务器接受到数据后写入txt文件。这时txt文件正常能够打开。

现在我用同样的方法读取android录音出来的.amr文件发送到服务器并写入.amr文件中,会出现文件损坏无法打开的问题。

基于此,感觉自己平时只注重软件功能的实现而不注重计算机原理的弊端出现了。出现了一些自己也觉得很幼稚的问题:
1:网络之间是如何传输数据的?
我将音频文件读取出来转换成二进制传输到服务端,服务端怎么将这些二进制恢复成原来的文件呢?

2:如何解决上面说的文件损坏无法打开的问题?

还是说我的理解一开始就是错的,感觉将音频文件读取出来就是不行?而应该用什么方法将音频文件进行转换才能传送呢?

客户端android代码:


 mConnection.connect(wsuri, new WebSocketHandler() {

 @Override
 public void onOpen() {
 Log.d(TAG, "Status: Connected to " + wsuri);

 InputStream is = null;
 try {
         is = new FileInputStream(_file);
     } catch (FileNotFoundException e) {
         e.printStackTrace();
     }

 byte[] bytes = new byte[1024];
 int len = 0;

 try {
        while((len=is.read(bytes))!=-1)
        {
            Log.d(TAG, "senBinaryMessage: " + bytes);
            mConnection.sendBinaryMessage(bytes);
        }
        is.close();
     } catch (IOException e) {
        e.printStackTrace();
        }                  
     }

}

服务端代码:


 $worker->onMessage = function($connection, $data)
{
    $filePath="/Users/myname/Desktop/php/";  
    if (!file_exists($filePath)){//如果指定文件夹不存在,则创建文件夹  
        mkdir($filePath , 0777);  
    }  

    $name=$filePath.'voice'.'.amr';  
    $fp = fopen ($name,"a");  

    if (fwrite ($fp,$data)){  
        echo "写入模板成功";  
    } else {  
        fclose ($fp);  
        echo "写入模板失败!";  
    }     
};

websocket Android workerman php

湯淺比吕美 9 years, 5 months ago

服务端代码不对,应该以追加的方式写文件


 $worker->onMessage = function($connection, $data)
{
    $filePath="/Users/myname/Desktop/php/";  
    if (!file_exists($filePath)){//如果指定文件夹不存在,则创建文件夹  
        mkdir($filePath , 0777);  
    }  
    $name=$filePath.'voice'.'.amr';
    // ===这里要以追加的方式写文件===
    file_put_contents($filePath.$name, $data, FILE_APPEND);
}

盗光者卡斯托尔 answered 9 years, 5 months ago

第一问题,一般网络通信都是基于tcp/ip进行通信,http还有socket都是封装了这些的。通信协议栈以下都是有操作系统维护,一般没有什么问题无
第二个问题 基于socket的网络通信还分有链接和无链接,这个传文件完全可以。什么datainputstream之类的都是可以的。我曾模拟过FTP服务器,跟文件格式无关的。建议考虑一下是否客户端的文件已经完整的传输到服务端了。

Kisa丶 answered 9 years, 5 months ago

建议你使用http api来做,因为socket过于底层,很多阻塞问题不是你可以解决的,你可以在服务器端做一个web api,安卓对于http的各项封装都很棒,可以试试 搜索一下apache 的httpclient类库

方寸却不能定夺 answered 9 years, 5 months ago

TCP工作方式:
https://zh.wikipedia.org/wiki/%E4%BC%A0%E8%BE%93%E6%8E%A7%E5%88%B6%E5%...

我认为文件损坏可能有两种原因
一. fopen 没有使用 b 标记

https://secure.php.net/manual/zh/function.fopen.php
在操作二进制文件时如果没有指定 'b' 标记,可能会碰到一些奇怪的问题,包括坏掉的图片文件以及关于 \r\n 字符的奇怪问题。

解决方法:
打开文件时加入 b 标记


 php


 fopen($name,"ab")

二. 写入成功后没有关闭文件。
这可能会导致:
1. 数据会停留在缓冲区,直到缓冲区已满或程序退出或垃圾回收时关闭文件才会把数据写入文件。(我太清楚php是否会对文件进行垃圾回收)
2. 可能程序退出或垃圾回收时关闭文件的顺序时随机的,这样将会导致数据前后顺序不一致。
用python做个测试


 python3


 a = open('test', 'ab')
a.write(b'123')
b = open('test', 'ab')
b.write(b'456')

b.close()
a.close()

test文件的内容为:


 456123

解决方法:
手动关闭文件


 php


 if (fwrite ($fp,$data)){  
    echo "写入模板成功";  
} else {
    echo "写入模板失败!";  
}
fclose($fp);

或者使用


 php


 fflush($fp);

来将数据写入缓冲区

因为对php不熟,我没有进行测试。

blabla兽 answered 9 years, 5 months ago

Your Answer