我正在完成一项学校任务,我必须建立一个获得TCP连接的服务器。然后这些连接传递数据。我使用poll()来查看是否存在新的连接请求,或者是否存在来自现有连接的传入数据。它与回送地址(127.0.0.1)一起使用。
当我有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然后与另一个连接时,我仍然有一些问题,但这是以后的问题:)
答案 0 :(得分:1)
在你的功能中
void add_poll(struct pollfd * polllist, tcpsock_t *client, tcpsock_t *server)
您正在重新分配包含套接字fd&#39; s的pollfd缓冲区,但是您在一个临时指针变量(polllist)中获取结果而不是您的全局变量&#34; poll_list&#34 ;。如果只能扩展内存,Realloc可能会也可能不会将内存移动到另一个位置。
当你回到你的循环中时,没有任何改变,你仍然使用相同的缓冲区 - 可能已被释放! - 包含服务器套接字和第一个连接,以及内存中的其他地方,有带有3个插座的缓冲区。
因此要么在指针上传递指针(struct pollfd ** polllist),要么设置&#34; poll_list&#34;变量而不是:)。
另外,如果我没有弄错,在你的循环中,当你这样做时:
if(poll_list[i+1].revents & POLLIN>0)
&#34;&gt;&#34;运营商的优先级高于&#34;&amp;&#34;运算符,因此它等同于:
if(poll_list[i+1].revents & (POLLIN>0))
只需删除&#34;&gt; 0&#34;,或在表达式周围加上括号