Linux C套接字:在recv调用时被阻止 [英] Linux C Socket: Blocked on recv call

查看:96
本文介绍了Linux C套接字:在recv调用时被阻止的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的应用程序中,我为一个简单的http服务器创建了一个线程,然后从我的应用程序中尝试连接到http服务器,但是在recv调用中控件被阻止/挂起.

In my application i have created a thread for a simple http server, then from within my application i tried to connect to http server but control is blocked/hanged on recv call.

但是,如果尝试使用linux GET命令连接到应用程序的http服务器,则我将成功连接到http服务器.

But if try to connect to my application's http server using linux GET command, I will be connected to http server successfully.

根据我对Google搜索的了解,我发现这不是正确的方法.

As per my understanding by searching the google i found that this is not the right approach.

但是,如果要执行此操作,则应以什么方式创建套接字,以便可以从应用程序内部连接http服务器.

But if i want to do this, in what should i create the sockets so that i can connect o my http server from within the application.

以下是我的http服务器套接字的创建方式

pthread_create(&pt_server, NULL, http_srvr, NULL);

//http server handler
void *http_server()
{
    int sockfd, new_fd;             
    struct sockaddr_in my_addr;     
    struct sockaddr_in their_addr;  
    socklen_t sin_size;
    struct sigaction sa;
    int yes=1;

    if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
    {
    perror("socket");
    exit(1);
    }

    if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1)
    {
    perror("setsockopt");
    exit(1);
    }

    my_addr.sin_family = AF_INET;               // host byte order
    my_addr.sin_port = htons(HTTP_PORT);        // short, network byte order
    my_addr.sin_addr.s_addr = INADDR_ANY;       // automatically fill with my IP
    memset(&(my_addr.sin_zero), '\0', 8);       // zero the rest of the struct

    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))== -1)
    {
    perror("bind");
    exit(1);
    }

    printf("Listening to sockets\n");
    if (listen(sockfd, BACKLOG) == -1)
    {
    perror("listen");
    exit(1);
    }

    sa.sa_handler = sigchld_handler; // reap all dead processes
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGCHLD, &sa, NULL) == -1)
    {
    perror("sigaction");
    exit(1);
    }

    printf("server: waiting for connections...\n");

    while(1) {  // main accept() loop
        sin_size = sizeof(struct sockaddr_in);
        if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr,&sin_size)) == -1)
        {
          perror("accept");
          continue;
        }
        printf("server: got connection from %s\n",inet_ntoa(their_addr.sin_addr));

        handle_connection(new_fd);
    }
}

以下是我对http服务器进行http POST的方式

  /* create socket */
  if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    return ERRSOCK;
  setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, 0, 0);


  /* connect to server */
  if (connect(s, &server, sizeof(server)) < 0) 
    ret=ERRCONN;
  else {
    if (pfd) *pfd=s;

    /* create header */
    if (proxy) {
      sprintf(header,
"%s http://%.128s:%d/%.256s HTTP/1.0\015\012User-Agent: %s\015\012%s\015\012",
          command,
          http_server1,
          http_port,
          url,
          http_user_agent,
          additional_header
          );
    } else {
      sprintf(header,
"%s /%.256s HTTP/1.0\015\012User-Agent: %s\015\012%s\015\012",
          command,
          url,
          http_user_agent,
          additional_header
          );
    }

    hlg=strlen(header);


    /* send header */   
    if (send(s,header,hlg,0)!=hlg)
      ret= ERRWRHD;

    /* send data */
    else if (length && data && (send(s,data,length,0)!=length) )
      ret= ERRWRDT;

    else {
      /* read result & check */
      ret=http_read_line(s,header,MAXBUF-1);

及以下是http_read_line的内容,并且在此函数中,recv调用被阻止

static int http_read_line (fd,buffer,max) 
     int fd; /* file descriptor to read from */
     char *buffer; /* placeholder for data */
     int max; /* max number of bytes to read */
{ /* not efficient on long lines (multiple unbuffered 1 char reads) */
  int n=0;
  while (n<max) {
    if (recv(fd,buffer,1,0)!=1) {
      n= -n;
      break;
    }
    n++;
    if (*buffer=='\015') continue; /* ignore CR */
    if (*buffer=='\012') break;    /* LF is the separator */
    buffer++;
  }
  *buffer=0;
  return n;
}

推荐答案

您已经告诉在我的应用程序中,我为一个简单的http服务器创建了一个线程,然后在我的应用程序中创建了一个线程 我试图连接到http服务器,但是在recv调用中控件被阻止/挂起."

You have told "In my application i have created a thread for a simple http server, then from within my application i tried to connect to http server but control is blocked/hanged on recv call."

这意味着recv永远不会返回0.现在,当recv函数将 返回0? ->当它得到一个TCP FIN段.看来您的服务器永远不会 向客户端发送TCP FIN段. 这里最有可能的原因是,您的客户端代码需要修改. 您正在从客户端发送数据,但是从不发送FIN, 所以我认为您的服务器功能将永远持续下去,并且它并没有 发送了FIN.这使得recv永远等待着.

That means the recv is never returning 0. Now when the recv function will return a 0? ->When it gets a TCP FIN segment. It seems that your server is never sending a TCP FIN segment to the client. The reason that is most likely here is that, your client code needs modification. You are sending data from from the client, but you are never sending the FIN, so I assume that your server function is continuing forever and it had not sent the FIN. This made the recv wait for ever.

在当前代码中,解决方法可能是添加一行

In the current code perhaps the fix is to add a line

else {
  /*Send the FIN segment, but we can still read the socket*/
  shutdown(s, SHUT_WR); 
  /* read result & check */
  ret=http_read_line(s,header,MAXBUF-1);

在这种情况下,关闭功能将发送TCP FIN,服务器功能可以返回,然后可能会进行适当的关闭.

In this case the shutdown function sends the TCP FIN and the server function can return and possibly then it would do a proper close.

在适当的关闭时间,客户端将接收到来自服务器的FIN.这将使recv返回0,而不是永远被阻塞.

And on a proper close, the FIN from the server will be received by the client. This would make the recv return 0, instead of getting blocked for ever.

现在,如果要继续从客户端进行任何进一步的数据传输,则需要重新连接,或者可能需要使用其他算法.

Now if you want to continue any further data transfer from the client, you need to again connect or may be you need to have some different algorithm.

我希望我的解释可以帮助解决当前问题.

I hope my explanation may help fix the current problem.

这篇关于Linux C套接字:在recv调用时被阻止的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆