我在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上写的内容而我不明白为什么,它在我的程序中做了同样的事情但是我没有读取标准输入,而是从套接字读取,但为了保持这个简单,我在这个例子中使用了stdin。
谢谢!
编辑:将我的len中的len更改为来自int的char并使用char读取我的thread_func,然后使用atoi()进行转换。
答案 0 :(得分:1)
write(0, &len, 1);
将len
的一个字节写入stdin
,但len
实际上有sizeof(int)
个字节。此外,当您使用read(0, &len, 1);
读取该值时,您只读取一个字节而不是sizeof(int)
。
此外,每次执行循环时都会读入len
并在流中接收随机值。除非您不小心将空字节读入len
,否则条件将始终为真,并且您将以无限循环结束。一旦你读完了整个流,下一次调用就会阻止。
因此,您应该正确地将消息的长度写入套接字并正确读取。此外,您还必须检查是否已经读取了所有字节以防止调用从阻塞中读取。
#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;
}
请注意,此代码仅在stdin未绑定到tty时有效。如果是,终端将在您自己阅读之前阅读它。 如果stdin绑定到tty,你需要一个管道或套接字对,因为loreb在他的回答中提到。
我尝试尽可能少地调整代码,只是为了让它工作。它仍然不好,而且容易出错。不幸的是,我没有提到任何显示如何做正确的事情。但也许这里的其他人可以提供参考。
答案 1 :(得分:1)
您无法写入fd 0并读取相同的数据! 你需要一些特殊的fd(管道,socketpair)来写一端并从另一端读取。 请注意,如果您尝试可能会得到数据写入但如果您的标准输入是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;
}
编辑:为了使其更清晰,这是添加太foobar的答案;我只是无法在评论中填写代码示例:)
答案 2 :(得分:0)
编辑:
感谢您的回答。 我解决了我的问题: 我的文件传输是通过块工作的,我首先发送大小读取到将要接收文件的一侧以及块本身之后。 但问题是,在接收数据的那一方,两个写入的一端都太快而另一端无法读取。 因此,我必须将serv与客户端同步,并在两次写入之间使用read(),并在两者之间进行读取以同步两者。也许这会对某人有所帮助。
代码:
客户端想要获取文件时:
#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的结构。