2016-08-12 71 views
1

我正在开展一项学校任务,在该任务中,我必须创建一个获取TCP连接的服务器。那些连接然后传递数据。我使用poll()来查看是否有新的连接请求,或者是否存在来自现有连接的传入数据。它与回送地址(127.0.0.1)一起使用。C中的轮询TCP连接

它工作正常,当我有1个连接,但是当我打开第二个,它停止轮询并等待来自新连接的数据。 奇怪的是,如果我打开第三个连接,它确实会提供第三个连接的数据,但仍然没有轮询,只是等待。

我读了很多关于它,我坚持了一会儿。

我在connmgr.c中编写了服务器代码(有很多printf来查找我的错误)。我会在下面解释:

#include <stdio.h> 
#include <stdlib.h> 
#include <inttypes.h> 
#include <assert.h> 

#include <unistd.h> 
#include <signal.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <sys/socket.h> 
#include <syslog.h> 
#include <poll.h> 

#include "connmgr.h" 

#define _GNU_SOURCE 

static FILE * write_file; 
struct pollfd *poll_list; 
int serversd; 
int conn_counter = 0; 

int dplist_errno; 

dplist_t * list = NULL; 
list_node_t * dummy = NULL; 


void * element_copy(void *element); 
void element_free(void **element); 
int element_compare(void *x, void *y); 


void add_poll(struct pollfd * polllist, tcpsock_t *client, tcpsock_t *server){ 
conn_counter++; 
polllist = realloc(polllist,sizeof(struct pollfd)*conn_counter+1); 
int clientsd; 
tcp_get_sd(client, &clientsd); 
polllist[conn_counter].fd= clientsd; 
//printf("fd in add_poll = %d \n",clientsd); 
polllist[conn_counter].events = POLLIN; 
} 
    int stop = 0; 
    tcpsock_t *server, *client; 

void connmgr_listen(int port_number){ 

    sensor_data_t data; 
dummy = malloc(sizeof(list_node_t)); 

write_file = fopen("sensor_data_recv", "w"); 

poll_list = malloc(sizeof(struct pollfd)); 
list = dpl_create(&element_copy, &element_free, &element_compare); 

if(tcp_passive_open(&server,port_number)!=TCP_NO_ERROR)exit(EXIT_FAILURE); 
tcp_get_sd(server, &serversd); 

poll_list[0].fd = serversd; 
poll_list[0].events = POLLIN; 

printf("server fd = %d \n",serversd); 

printf("start with fd %d = %d \n", 0,poll_list[0].fd); 

int bytes,result; 
int test = 0; 

while(1){ 

    test++; 
    int sd; 
    int return_value,i; 

    return_value = poll(poll_list,conn_counter+1,TIMEOUT); 

    if (return_value>0){ 
     if(poll_list[0].revents & POLLIN>0){ 
      printf("add client\n"); 

      tcpsock_t * requestclient; 
      if (tcp_wait_for_connection(server,&requestclient)!=TCP_NO_ERROR) exit(EXIT_FAILURE); 
      tcp_get_sd(requestclient, &sd); 
      dummy->sd = sd; 
      printf("inserted sd = %d \n",sd); 
      dummy->client = requestclient; 
      time(&(dummy->ts)); 
      list = dpl_insert_at_index(list, dummy, conn_counter,true); 



      //printf("sd from client = %d \n", tcp_get_sd(client, &sd)); 

      add_poll(poll_list, dummy->client, server); 
      printf("conn_counter = %d \n",conn_counter); 

     } 

     //for (i=0; i<conn_counter;i++){ 
     i=0; 
     while(i<conn_counter){ 
      if(poll_list[i+1].revents & POLLIN>0){ 

       printf("poll in %d \n",i+1); 

       dummy = (list_node_t *) dpl_get_element_at_index(list,i); 
       time(&(dummy->ts)); 
       client = dummy->client; 
       sd = dummy->sd; 

       /*for(int l = 0; l<conn_counter;l++){ 
         printf("sensor %d \n",l); 

       }*/ 

       bytes = sizeof(data.id); 
       printf("@ line %d en i = %d \n", __LINE__,i);result = tcp_receive(client,(void *)&data.id,&bytes); 

       bytes = sizeof(data.value); 
       printf("@ line %d \n", __LINE__);result = tcp_receive(client,(void *)&data.value,&bytes); 

       bytes = sizeof(data.ts); 
       printf("@ line %d \n", __LINE__);result = tcp_receive(client,(void *)&data.ts,&bytes); 


       if ((result==TCP_NO_ERROR) && bytes){ 
       printf("sensor id = %" PRIu16 " - temperature = %g - timestamp = %ld\n", data.id, data.value, (long int)data.ts); 
         } 

       else{ 
        if(result == TCP_CONNECTION_CLOSED){printf("peer left \n");} 
        else{"error in peerconnection \n";} 
        tcp_close(&client); 
        list = dpl_remove_at_index(list, i, true); 
        } 
       fflush(stdout); 
      } 
      if (poll_list[i+1].revents & POLLHUP){ 
       printf("client disconnected \n"); 
       poll_list[conn_counter+1].fd=-1; 
       poll_list[conn_counter+1].events=0; 
       fflush(stdout); 
      }i++; 
     }  
    } 
    //if(return_value<0){exit(EXIT_FAILURE);} 
    //if(stop == 1){break;} 
    printf("end of while %d \n",test); 



} 

一旦服务器在tcp_passive_open已经开始,它将直到该RETURN_VALUE高启动轮询。然后它检查POLLIN是否在[0],这意味着一个新的连接请求。如果没有,我检查poll_list中的所有连接,从1开始直到conn_counter。如果没有,我检查一个POLLHUP并将该客户端的fd设置为-1,所以poll()将忽略这个。

我认为它应该在某处我使用while循环来检查POLLIN是否来自其中一个连接,因为我可以添加连接没有问题。

dpl _...函数来自我自己写的dubble-linked-list库,应该可以正常工作。他们创建一个列表,在索引处获取一个元素...该列表使用3个回调函数。

tcp _...函数是我从教授那里得到的函数。 tcpsock.h文件应该提供足够的信息:

typedef struct tcpsock tcpsock_t; 

int get_size_tcpsock(); 

// All functions below return TCP_NO_ERROR if no error occurs during execution 

int tcp_passive_open(tcpsock_t ** socket, int port); 
/* Creates a new socket and opens this socket in 'passive listening mode' (waiting for an active connection setup request) 
* The socket is bound to port number 'port' and to any active IP interface of the system 
* The number of pending connection setup requests is set to MAX_PENDING 
* The newly created socket is returned as '*socket' 
* This function is typically called by a server 
*/ 

int tcp_active_open(tcpsock_t ** socket, int remote_port, char * remote_ip); 
/* Creates a new TCP socket and opens a TCP connection to the system with IP address 'remote_ip' on port 'remote_port' 
* The newly created socket is return as '*socket' 
* This function is typically called by a client 


int tcp_close(tcpsock_t ** socket); 
/* The socket '*socket' is closed , allocated resources are freed and '*socket' is set to NULL 
* If '*socket' is connected, a TCP shutdown on the connection is executed 
*/ 

int tcp_wait_for_connection(tcpsock_t * socket, tcpsock_t ** new_socket); 
/* Puts the socket 'socket' in a blocking wait mode 
* Returns when an incoming TCP connection setup request is received 
* A newly created socket identifying the remote system that initiated the connection request is returned as '*new_socket' 
*/ 

int tcp_send(tcpsock_t * socket, void * buffer, int * buf_size); 
/* Initiates a send command on the socket 'socket' and tries to send the total '*buf_size' bytes of data in 'buffer' (recall that the function might block for a while) 
* The function sets '*buf_size' to the number of bytes that were really sent, which might be less than the initial '*buf_size' 
*/ 

int tcp_receive (tcpsock_t * socket, void * buffer, int * buf_size); 
/* Initiates a receive command on the socket 'socket' and tries to receive the total '*buf_size' bytes of data in 'buffer' (recall that the function might block for a while) 
* The function sets '*buf_size' to the number of bytes that were really received, which might be less than the inital '*buf_size' 
*/ 

int tcp_get_ip_addr(tcpsock_t * socket, char ** ip_addr); 
/* Set '*ip_addr' to the IP address of 'socket' (could be NULL if the IP address is not set) 
* No memory allocation is done (pointer reference assignment!), hence, no free must be called to avoid a memory leak 
*/ 

int tcp_get_port(tcpsock_t * socket, int * port); 
/* Return the port number of the 'socket' 
*/ 

int tcp_get_sd(tcpsock_t * socket, int * sd); 
/* Return the socket descriptor of the 'socket' 
*/ 

感谢您阅读本文,我希望你能帮助我!

ps的,我有一些问题,当我断开TCP,然后用另一个连接,但有问题的后:)

回答

1

在你的函数

void add_poll(struct pollfd * polllist, tcpsock_t *client, tcpsock_t *server) 

你重新分配包含套接字fd的pollfd缓冲区,但是您将得到一个临时指针变量(polllist)而不是全局变量“poll_list”的结果。 Realloc可能会或可能不会将内存移动到另一个位置,如果它可以扩展它。

当你回到你的循环时,什么都没有改变,你仍然使用相同的缓冲区 - 可能已经被释放! - 包含服务器套接字和第一个连接,以及内存中的其他地方,带3个插座的缓冲区。

所以要么在指针(struct pollfd ** polllist)上传递指针,要么设置“poll_list”变量:)。

而且,如果我没有记错的话,在你的循环,当你这样做:

if(poll_list[i+1].revents & POLLIN>0) 

的“>”操作符比“&”运算符优先级高,所以它等同于:

if(poll_list[i+1].revents & (POLLIN>0)) 

只为你的答案删除“> 0”,或把括号在你的表达

+0

嘿嘿,谢谢,但我改变了你说的和它保持不变......我现在做“poll_list =的realloc(poll_li st,sizeof(struct pollfd)* conn_counter + 1);' ,但它没有效果。你有任何其他可能的解决方案? :) –

+0

要小心你的'sizeof(struct pollfd)* conn_counter + 1',因为它等于'(sizeof(struct pollfd)* conn_counter)+ 1',与sizeof(struct pollfd)*( conn_counter + 1)'。 除此之外,你是否也改变了'polllist [conn_counter] .fd = clientsd;'(以及下面的类似行)?和'POLLIN> 0'的东西? 你能解释一下你的意思吗?“如果我打开第三个连接,它确实给出了第三个连接的数据**,但仍然没有轮询,只是等待”? (另外,请确保在创建新的pollset时清除“revent”字段) – KailoKyra

+0

是的,我做了更改,但没有任何帮助。我的意思是,如果我打开第二个连接,它会停止轮询第一个连接,并仅从第二个连接发送数据。 (这发生在没有轮询的情况下,因为它不再循环通过wile-loop,只是等待数据,我可以看到,因为虚拟'测试结束') 如果我打开第三个连接,它将从第二个和第三次连接,但又没有轮询,只是在等待数据,而没有循环。所以就像你说的,也许那里保持高的POLLIN旗帜? –