gpt4 book ai didi

c++ - 在 TCP 线程服务器 C++ 中传输文件

转载 作者:太空宇宙 更新时间:2023-11-04 05:36:32 24 4
gpt4 key购买 nike

大家好,我有一个小问题,我应该从服务器(带有线程的 TCP 服务器到客户端)传输文件。问题出现在传输结束时,客户端收到了文件,但它卡住了,我无法再与其通信。

这是服务器

int main(int argc, char *argv[])
{
int socket_desc, client_sock, c;
struct sockaddr_in server, client;

//Create socket
socket_desc = socket(AF_INET, SOCK_STREAM, 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
puts("Socket created");

//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(2025);

//Bind
if (bind(socket_desc, (struct sockaddr *) &server, sizeof(server)) < 0)
{
//print the error message
perror("bind failed. Error");
return 1;
}
puts("bind done");

//Listen
listen(socket_desc, 5);

//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);

int enable = 1;

//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
pthread_t thread_id;

while ((client_sock = accept(socket_desc,
(struct sockaddr *) &client,
(socklen_t*) &c)))
{
puts("Connection accepted");
if (setsockopt(client_sock,
SOL_SOCKET,
SO_REUSEADDR,
&enable,
sizeof(int)) < 0)
error("setsockopt(SO_REUSEADDR) failed");
if (pthread_create(&thread_id,
NULL,
connection_handler,
(void*) &client_sock) < 0)
{
perror("could not create thread");
return 1;
}

//Now join the thread , so that we dont terminate before the thread
pthread_join(thread_id, NULL);
puts("Handler assigned");
}

if (client_sock < 0)
{
perror("accept failed");
return 1;
}

return 0;
}

void *connection_handler(void *socket_desc)
{
printf("Enter in handler");
//Get the socket descriptor
int sock = *(int*) socket_desc;
send_problemo(sock);

return 0;
}

这是发送函数,我认为这是真正的问题

int send_problemo(int *sock)
{
ssize_t read_return;
char *file_path = "Problems/1.txt";
char buffer[BUFSIZ];
int filefd;
filefd = open(file_path, O_RDONLY);
char end[2] = "1";
if (filefd == -1)
{
perror("open");
exit (EXIT_FAILURE);
}
while (1)
{
read_return = read(filefd, buffer, BUFSIZ);
if (read_return == 0)
{
printf("este 0 \n");
break;
}
if (read_return == -1)
{
perror("read");
exit (EXIT_FAILURE);
}
if (write(sock, buffer, read_return) == -1)
{
perror("write");
exit (EXIT_FAILURE);
}
}
// close(sock);
close(filefd);
}

客户端正常连接,并在该函数中接收文件

int recive_problemo(int *sockfd)
{
char *file_path = "path.c";
char buffer[BUFSIZ];
ssize_t read_return;
int filefd;
filefd = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (filefd == -1)
{
perror("open");
exit (EXIT_FAILURE);
}

do
{
read_return = read(sockfd, buffer, BUFSIZ);
if (read_return == -1)
{
perror("read");
exit (EXIT_FAILURE);
}
if (write(filefd, buffer, read_return) == -1)
{
perror("write");
exit (EXIT_FAILURE);
}
} while (read_return > 0);
close(filefd);
}

我设法解决了这个问题。如果我从服务器关闭(SHUT_WR),客户端不再卡住,但我想与它进一步通信。如果我从客户端转移到服务器,也具有相同的功能,它工作完美,所以有人可以帮助我吗?

最佳答案

do
{
read_return = read(sockfd, buffer, BUFSIZ);
// error handling
// file write
} while (read_return > 0);

将继续循环,直到套接字关闭或出现错误。它无法判断文件是否已完成。

常见的解决方案是关闭套接字(但您不希望这样做)并建立通信协议(protocol),以便您知道文件何时完成并可以退出循环。

为了让事情变得非常简单,我建议在发送文件之前发送文件的长度。循环现在看起来像:

uint64_t file_len;
read_return = recv(sockfd, &file_len, sizeof(file_len), MSG_WAITALL);
if (read_return == sizeof(file_len))
{
// Strongly consider handling the endian of file_len here
while (file_len)
{
size_t readmax = std::min(file_len, BUFSIZ);
read_return = read(sockfd, buffer, readmax);
if (read_return > 0)
{
if (write(filefd, buffer, read_return) == -1)
{
perror("write");
exit (EXIT_FAILURE);
}
file_len -= read_return;
}
else
{
// handle error
// exit loop if not recoverable
}
}
}

服务器端负责获取和发送文件的长度。我不会深入讨论这个问题,因为有太多不同的方法可以获取文件的长度。选择您最喜欢的。

Documentation on recv and MSG_WAITALL .

关于c++ - 在 TCP 线程服务器 C++ 中传输文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47823736/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com