从线程中的stdin读取以写入c中的文件

时间:2014-07-23 10:18:54

标签: c multithreading

我在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()进行转换。

3 个答案:

答案 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的结构。