从线程中的标准输入读取以写入 c 中的文件
Posted
技术标签:
【中文标题】从线程中的标准输入读取以写入 c 中的文件【英文标题】:Reading from stdin in a thread to write in a file in c 【发布时间】:2014-07-23 10:18:53 【问题描述】:我正在 c 中使用 TCP 创建一个 FTP 服务器。我的文件传输出现问题,我希望能够从客户端向/从服务器“放置”或“获取”文件。 我正在使用 select() 处理多连接并使用线程来处理文件传输。 我创建了一个简单的 .c 示例来总结我的问题:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void *read_stdin(void * null)
int fd;
int len;
char ret;
char buff[1024];
fd = open("dest", O_RDWR | O_TRUNC | O_CREAT, 0600);
len = 1;
while (len)
ret = read(0, &len, 1);
len = atoi(ret);
if (len)
read(0, buff, len);
write(fd, buff, len);
return (null);
int main()
pthread_t t;
int fd;
char len;
char buff[1024];
pthread_create(&t, NULL, &read_stdin, NULL);
fd = open("source", O_RDONLY);
while ((len = read(fd, buff, 1024)))
write(0, &len, 1);
write(0, buff, len);
write(0, "0", 1);
pthread_join(t, NULL);
return (0);
现在我的问题是线程中的 read() 被阻塞了,它没有从主进程读取我在 STDIN 上写的内容,我不明白为什么,它在我的程序中做同样的事情吗但不是从标准输入读取,而是从套接字读取,但为了简单起见,我在此示例中使用了标准输入。
谢谢!
编辑:将 main 中的 len 从 int 更改为 char,并使用 char 读取我的 thread_func,然后使用 atoi() 进行转换。
【问题讨论】:
您是否将您的套接字设置为非阻塞——fcntl(sockfd, F_SETFL, O_NONBLOCK);
?你真的在使用read()
从套接字读取吗?
并行运行 read
不会使其成为非阻塞的。您可能想在STDIN_FILENO
上select
阅读。
当我说它阻塞时,我的意思是它没有读取我在主进程中写的内容,我不希望它是非阻塞的,我希望它读取我的我在 STDIN 上写作
这段代码有很多问题:写入标准输入,int
/char
到处不匹配,在char
上调用atoi()
,不检查返回值。 .
【参考方案1】:
write(0, &len, 1);
将len
的一个字节写入stdin
,但len
实际上有sizeof(int)
字节。此外,当您使用read(0, &len, 1);
读取该值时,您只会读取一个字节而不是sizeof(int)
。
此外,您在每次执行循环时都会读取len
并在流中接收随机值。除非您不小心将空字节读入len
,否则条件将始终为真,您最终会陷入无限循环。读取整个流后,下一次调用 read 将阻塞。
所以你应该正确地将消息的长度写入套接字并正确读回。此外,您还必须检查您是否已经读取了所有字节,以防止调用 read 阻塞。
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
void* read_stdin(void * null)
int fd;
char len;
char ret;
char buff[255];
fd = open("dest", O_RDWR | O_TRUNC | O_CREAT, 0600);
len = 1;
while (len)
len = read(0, &len, sizeof(len));
if (len)
read(0, buff, len);
write(fd, buff, len);
close(fd);
return NULL;
int main()
pthread_t t;
int fd;
char len;
char buff[128];
pthread_create(&t, NULL, &read_stdin, NULL);
fd = open("source", O_RDONLY);
while (len = read(fd, buff, 128)) // you can only read 128 characters as len is a signed char (assuming an eight bit byte)
write(0, &len, sizeof(len));
write(0, buff, len);
//write(0, "0", 1);
close(0);
close(fd);
pthread_join(t, NULL);
return 0;
请注意,此代码仅在标准输入未绑定到 tty 时才有效。如果是,在您自己阅读之前,它会被终端读取。 如果标准输入绑定到 tty,您将需要一个管道或套接字对,正如 loreb 在他的回答中提到的那样。
我尝试尽可能少地调整您的代码,以使其正常工作。它仍然不好,而且容易出错。不幸的是,我没有提及任何显示如何正确操作的内容。但也许这里的其他人可以提供参考。
【讨论】:
确实你是对的,我应该给 write 4 的第三个 arg 来写 int 或者使用一个 char 并且只写一个字节。我更新了我的更改,但它并没有改变我在线程函数中读取的不是读取 len 值或缓冲区的事实。 @user3795248 我很快就会回家,然后我可以进一步帮助您并为您提供一些代码。【参考方案2】:您不能写入 fd 0 并通过 read 读回相同的数据! 您需要某种特殊类型的 fd(管道、套接字对)在一端写入并从另一端读取。 请注意,如果您尝试,您可能会得到数据已写入但如果您的标准输入是 tty 则永远不会读取,请参阅以下程序(尝试从终端读取,然后使用重定向输入):
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define TRACE(wtf) \
fprintf(stderr, "%u: %s...\n", __LINE__, wtf)
#define BUF 123
int main()
char buf[BUF] = "abc\n";
char got[BUF];
int n;
/* writes to tty, appears on terminal, but it's NOT READABLE FROM STDIN */
if(write(0, buf, sizeof buf) < 0)
perror("write");
return 111;
TRACE("wok");
/* read should block (until you type something) */
if((n = read(0, got, sizeof got)) < 0)
perror("read");
return 111;
TRACE("rok");
if(memcmp(buf, got, n) != 0)
return printf("wtf?\n");
return 0;
编辑:为了更清楚,这也是 addition foobar 的答案;我只是无法将代码示例放在评论中:)
【讨论】:
【参考方案3】:编辑:
感谢您的回答。 我解决了我的问题: 我的文件传输是按块进行的,我首先将要读取的大小发送到将要接收文件的一侧,然后就在块本身之后。 但问题是,在将要接收数据的一侧,两个写入都在一端进行得太快,而在另一端无法读取。 因此,我必须在两次写入之间使用 read() 将 serv 与客户端同步,并在两次读取之间进行一次写入以同步它们。也许这会对某人有所帮助。
代码:
客户端想要获取文件时:
#include <sys/types.h>
#include <sys/socket.h>
#include <inttypes.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include "client.h"
static int write_to_file(int fd, int cs)
int len;
char buff[2048];
char size[24];
memset(size, 0, 24);
read(cs, size, 24);
len = atoi(size);
memset(buff, 0, 2048);
if (len)
write(cs, "\n", 1);
len = read(cs, buff, len);
write(fd, buff, len);
return (len);
int get_file_content(t_client *c, char *filename)
int len;
int fd;
if ((fd = open(filename, O_RDWR | O_TRUNC | O_CREAT, 0600)) == -1)
return (my_perror(strerror(errno)));
write(c->cs, c->cmd, strlen(c->cmd));
len = 1;
while (len)
len = write_to_file(fd, c->cs);
close(fd);
printf("ok\n");
return (0);
发送文件的“get”服务器端:
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include "server.h"
static void write_to_sck(int len, char *buff, t_fd *now)
char size[24];
char tmp[3];
memset(size, 0, 24);
memset(tmp, 0, 2);
sprintf(size, "%d\n", len);
write(now->sck, size, strlen(size));
read(now->sck, tmp, 1);
write(now->sck, buff, len);
void *write_file_content(void *ptr)
t_fd *now;
t_files *file;
int len;
char buff[2048];
now = (t_fd *)ptr;
find_file(now->head, &file, now->curr_file);
pthread_mutex_lock(&file->m);
if ((file->fd = open(file->name, O_RDONLY)) == -1)
write(now->sck, strerror(errno), strlen(strerror(errno)));
return (ptr);
memset(buff, 0, 2048);
while ((len = read(file->fd, buff, 2048)))
write_to_sck(len, buff, now);
memset(buff, 0, 2048);
write(now->sck, "0\n", 1);
close(file->fd);
pthread_mutex_unlock(&file->m);
now->threaded = 0;
return (0);
int get_func(t_fd *now)
char **tab;
if (!(tab = str_to_wordtab(now->cmd)))
write(now->sck, "ko\n", 3);
return (my_perror("error: str_to_wordtab() in get_func()"));
if (access(tab[1], R_OK) == -1)
free_tab(tab);
return (write(now->sck, strerror(errno), strlen(strerror(errno))));
if (add_new_file(now, tab[1]))
free_tab(tab);
return (write(now->sck, "ko\n", 3));
now->threaded = 1;
pthread_create(&now->t, NULL, write_file_content, now);
free_tab(tab);
return (0);
我的服务器在 t_fd * 中有一个包含他和他的客户端的套接字链接列表,并且客户端在 t_client 中有一个包含他的 fd 的结构。
【讨论】:
以上是关于从线程中的标准输入读取以写入 c 中的文件的主要内容,如果未能解决你的问题,请参考以下文章