首页 > 解决方案 > 与发送文件的选项聊天

问题描述

我想创建一个带有发送文件选项的简单 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 方法被调用,然后我选择文件,我想发送这个文件,并与其他客户端下载它。

标签: javactcp

解决方案


好的,服务器在接收文件时有一个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);

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


推荐阅读