【问题标题】:Chat with option to send file与发送文件的选项聊天
【发布时间】:2019-06-02 09:55:53
【问题描述】:

我想创建一个带有发送文件选项的简单 TCP 聊天。
向其他客户端发送消息有效,但发送文件无效。我的聊天只发送几个字节的文件。

聊天的工作原理是:服务器启动并等待客户端,客户端连接到服务器,他们可以通过服务器向其他客户端发送消息。我想允许与文件相同。

服务器是用 C 写的,客户端是用 Java 写的(我有这样的指导方针)。

服务器:

    for (i = 0; i < max_clients; i++) {
        sd = client_socket[i]; 

        memset(buffer, 0, 10000);
        if (FD_ISSET( sd , &readfds)) {
            if ((valread = read( sd , buffer, 1024)) == 0) {
                getpeername(sd, (struct sockaddr*)&address, (socklen_t*)&addrlen); 
                printf("Host disconnected , ip %s , port %d \n" , 
                    inet_ntoa(address.sin_addr) , ntohs(address.sin_port)); 



                close( sd ); 
                client_socket[i] = 0; 
            } 
            else {
                // When message "start" arrived download the file and send it back to other clients
                if (strcmp(buffer, "start") == 0) {
                    uint8_t buff[10000];
                    // Read chunks of file
                    while (read( sd , buff, sizeof(buff)) > 0) {

                        // Sending chunks of file to other clients
                        for(j=0; j<max_clients; j++) {
                            int outSock = client_socket[j];
                            if(outSock != master_socket && outSock != sd) {
                                send(outSock , buff , sizeof(buff) , 0 ); 
                            }
                    }

                    }
                } else {

                    buffer[valread] = '\0'; 
                    for(j=0; j<max_clients; j++) {
                        int outSock = client_socket[j];
                        if(outSock != master_socket && outSock != sd) {
                            send(outSock , buffer , strlen(buffer) , 0 ); 
                        }
                    }

                }

            } 
        } 
    }

客户:

@FXML
void sendFile(ActionEvent event) {
    FileChooser fileChooser = new FileChooser();
    File file = fileChooser.showOpenDialog(null);

    // Send "start" message to let server know that I'm going to send a file
    out.println("start");
    out.flush();

    try {

        FileInputStream fis = new FileInputStream(file);
        BufferedInputStream bis = new BufferedInputStream(fis);

        //Get socket's output stream
        OutputStream os = clientSocket.getOutputStream();

        //Read File Contents into contents array
        byte[] contents;
        long fileLength = file.length();
        long current = 0;

        while(current!=fileLength){
            int size = 10000;
            if(fileLength - current >= size)
                current += size;
            else{
                size = (int)(fileLength - current);
                current = fileLength;
            }
            contents = new byte[size];
            bis.read(contents, 0, size);
            os.write(contents);
            System.out.print("Sending file ... "+(current*100)/fileLength+"% complete!");
        }

        os.flush();
        System.out.println("File sent successfully!");

    } catch(Exception e) {

    }
}

public ChatWindowController() {

    try {
        clientSocket = new Socket("127.0.0.1", 54000);
        outToServer = new DataOutputStream(clientSocket.getOutputStream());
        inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        out = new PrintWriter(clientSocket.getOutputStream(), true);

        thread = new Thread() {
            @Override
            public void run() {
                try {

                    while(isRunning) {
                        if (ta_display != null) {
                            String message = inFromServer.readLine();
                            if (!isDownloadingFile) {
                                System.out.println(message);
                                ta_display.appendText(message + '\n');

                                if (message.equals("start")) {
                                    isDownloadingFile = true;
                                }
                            } else {

                                byte[] contents = new byte[10000];

                                //Initialize the FileOutputStream to the output file's full path.
                                FileOutputStream fos = new FileOutputStream("/example/test.png");
                                BufferedOutputStream bos = new BufferedOutputStream(fos);
                                InputStream is = clientSocket.getInputStream();

                                //No of bytes read in one read() call
                                int bytesRead = 0;

                                while((bytesRead=is.read(contents))!=-1)
                                    bos.write(contents, 0, bytesRead);

                                bos.flush();

                                System.out.println("File saved successfully!");

                            }
                        }

                    }

                } catch(Exception e) {
                    e.printStackTrace();
                }
            }
        };

        thread.start();
    } catch(Exception e) {
        e.printStackTrace();
    }
}

当我点击按钮 sendFile 方法被调用,然后我选择文件,我想发送这个文件,并与其他客户端下载它。

【问题讨论】:

  • 好的,那么,您是否隔离了问题,确定了导致问​​题的代码部分?您是否在日志中遇到任何错误消息?请确保在寻求帮助之前尽职尽责。
  • 我没有收到任何错误。当我发送一个文件时,其他客户端只得到这个文件的几个字节。
  • “我没有收到任何错误。.. } catch(Exception e) { } 使用该代码,您无法知道是否有错误。不要忽视异常!他们准确地告诉我们出了什么问题。除非实现了日志记录,否则至少调用Throwable.printStackTrace()

标签: java c tcp


【解决方案1】:

我在https://github.com/foreverpersist/socket/blob/master/chatroom.c写了一个类似的聊天例子。

文件传输是通过P2P实现的

  1. 服务器将发送者和接收者的信息告诉&lt;IP:PORT&gt;s。
  2. 发送方和接收方直接相互连接。
  3. 发送方将文件发送给接收方。
  4. 发送方和接收方关闭连接。

在你的项目中,当传输路径为Sender -&gt; Server -&gt; Receiver的文件时,如果你不小心处理,大文件的内容可能会不完整。所以,我只是传输路径为Sender -&gt; Receiver的文件。

【讨论】:

    【解决方案2】:

    好的,服务器接收文件时出现bug:

    //client sends 10000 bytes of data in chunks of unknown size
    
    //receive one chunk of unknown size
    while (read( sd , buff, sizeof(buff)) > 0) {
        for(j=0; j<max_clients; j++) {
            int outSock = client_socket[j];
            if(outSock != master_socket && outSock != sd) {
                // Send 10000 bytes aka the received chunk and whatever else is in the buffer to all clients
                send(outSock , buff , sizeof(buff) , 0 ); 
            }
        }
    

    您需要先接收所有数据,然后将其发送给客户端,或者只发送块大小的多个字节,例如在客户端的文件写入器中或如下:

    int chunk = 0;
    while ((chunk = read( sd , buff, sizeof(buff))) > 0) {
        ...
        send(outSock , buff , chunk , 0);
    

    我也不确定客户端文件写入代码是否有效,你应该确保没有以下消息被意外写入文件。

    【讨论】:

    • 我试过了,客户端发送的文件只有20kb而不是1mb左右。
    • 你检查过服务器接收了多少数据吗?这些 20kb 是否与发送文件的前 20kb 相同?
    • 当我尝试打印块的大小时,没有显示任何内容。
    • 这可能是由各种问题引起的,要么 A) 让输出显示,可能是通过提出一个新问题或 B) 找到另一种直接从服务器获取消息的方法,可能是通过记录到文件,调试,在另一个网络端口上发送调试消息等......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-01
    • 1970-01-01
    • 2012-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多