[英]C sockets - Blocked on select
我正在使用一個客戶端服務器程序,該程序使用select()調用來偵聽多個套接字。 但是我的select調用被阻止了,盡管我在那些套接字之一中有一條消息,select()調用無法識別它,並且仍然在那兒無限期地等待。
該程序中有2個實體,一個主實體和一個客戶。 主機知道它將處理的客戶端數量,並等待客戶端連接到它。 收到客戶確認后,它將存儲其信息。 一旦所有客戶端都連接好,它就會將其鄰近客戶端的信息發送給每個客戶端,以便它可以形成一個網絡。 在這里,我使用select()監視許多套接字,master的每個子項都有一個套接字連接到它,客戶端有3個主要的套接字s1-與master對話-子級在此套接字附近監聽連接-它的鄰居等待連接的套接字。(即鄰居中的S2)p-是來自鄰居的連接結果的套接字(接受s2-返回),我使用select來監聽服務器,它自己的套接字用於傳入連接一次。
最初,我的服務器向客戶端中的一個發送字符串“ hello”,該客戶端接收到此消息並將其傳遞給鄰居,以這種方式,當字符串返回到從服務器接收到該消息的第一個孩子時,它將傳遞它到它的鄰居。 但是,盡管所有子級都在select()中等待輸入。 是什么原因造成的?
void main(int argc, char **argv) {
int s1, s2, n, server_port, sc1, sc2, rv, rc, left_peer_port;
int peer_port;
fd_set writefds, readfds;
struct timeval tv;
struct hostent *server_info, *child_info, *left_peer_info;
int start_flag = 0;
struct sockaddr_in server, peer, incoming;
char host_child[64];
char *left_host = malloc(1);
char *right_host = malloc(1);
char buf1[256];
char buf2[256];
server_port = atoi(argv[2]);
//speak to peer using this
s2 = socket(AF_INET, SOCK_STREAM, 0);
if (s2 < 0) {
perror("socket:");
exit(s2);
}
peer_port = server_port + 1;
gethostname(host_child, sizeof host_child);
child_info = gethostbyname(host_child);
if (child_info == NULL) {
fprintf(stderr, "%s: host not found (%s)\n", argv[0], host_child);
exit(1);
}
peer.sin_family = AF_INET;
memcpy(&peer.sin_addr, child_info->h_addr_list[0], child_info->h_length);
int changeport = 0;
do {
peer.sin_port = htons(peer_port);
rc = bind(s2, (struct sockaddr *) &peer, sizeof(peer));
if (rc < 0) {
//perror("bind:");
peer_port++;
changeport = 1;
//exit(rc);
} else {
changeport = 0;
}
} while (changeport == 1);
if (listen(s2, 100) == -1) {
perror("listen");
exit(3);
}
//Now talk to server
server_info = gethostbyname(argv[1]);
if (server_info == NULL) {
fprintf(stderr, "%s: host not found\n", argv[0]);
exit(1);
}
// pretend we've connected both to a server at this point
//speak to server using this
s1 = socket(AF_INET, SOCK_STREAM, 0);
if (s1 < 0) {
perror("socket:");
exit(s1);
}
server.sin_family = AF_INET;
server.sin_port = htons(server_port);
memcpy(&server.sin_addr, server_info->h_addr_list[0], server_info->h_length);
//To talk to the server
sc1 = connect(s1, (struct sockaddr *) &server, sizeof(server));
if (sc1 < 0) {
perror("connect:");
exit(sc1);
}
int send_len;
char *str = malloc(1);
sprintf(str, "%d", peer_port);
printf("\nport-here=%s\n", str);
send_len = send(s1, str, strlen(str), 0);
if (send_len != strlen(str)) {
perror("send");
exit(1);
}
int recv_len;
char buf[100];
int ref = 0;
int recv_stage = 0;
int start_id;
recv_len = recv(s1, buf, 34, 0);
if (recv_len < 0) {
perror("recv");
exit(1);
}
buf[recv_len] = '\0';
char *temp_port;
if (!strcmp("close", buf))
printf("%s", buf);
//break;
else {
char *temp_buffer = malloc(1);
char *id = malloc(100);
char *pp = malloc(1);
strcpy(temp_buffer, buf);
char *search = ":";
temp_port = strtok(temp_buffer, search);
strcpy(buf, temp_port);
printf("temp_name%s", temp_port);
temp_port = strtok(NULL, search);
strcpy(pp, temp_port);
printf("temp_port%s", temp_port);
temp_port = strtok(NULL, search);
strcpy(id, temp_port);
printf("id%s", temp_port);
strcpy(temp_port, pp);
printf("\nbuf=%s\n", buf);
printf("\nport=%s\n", temp_port);
printf("\nid=%s\n", id);
start_id = atoi(id);
}
//To send packet to its neighbour
left_peer_info = gethostbyname(buf);
printf("\nleft host=%s\n", buf);
if (left_peer_info == NULL) {
fprintf(stderr, "%s: host not found\n", left_host);
exit(1);
}
left_peer_port = atoi(temp_port);
int neighbour_socket;
struct hostent *neighbour_info;
struct sockaddr_in neighbour;
neighbour_socket = socket(AF_INET, SOCK_STREAM, 0);
if (neighbour_socket < 0) {
perror("socket:");
exit(neighbour_socket);
}
neighbour_info = left_peer_info;
neighbour.sin_family = AF_INET;
neighbour.sin_port = htons(left_peer_port);
memcpy(&neighbour.sin_addr, neighbour_info->h_addr_list[0], neighbour_info->h_length);
printf("\nconnected to port %d\n", left_peer_port);
//To talk to the neighbour
printf("\ncomes here\n");
//Listen on this socket connection for potato
int send_peer_len;
int nfds;
nfds = MAX(MAX(neighbour_socket, s2), s1);
// clear the set ahead of time
FD_ZERO(&writefds);
// add our descriptors to the set
FD_SET(neighbour_socket, &writefds);
FD_SET(s1, &writefds);
FD_SET(s2, &writefds);
//FD_SET(s2, &writefds);
FD_ZERO(&readfds);
FD_SET(neighbour_socket, &readfds);
FD_SET(s1, &readfds);
FD_SET(s2, &readfds);
//select()
// since we got s2 second, it's the "greater", so we use that for
// the n param in select()
//n = s1 + 1;
// wait until either socket has data ready to be recv()d (timeout 10.5 secs)
tv.tv_sec = 10;
tv.tv_usec = 500000;
int fds[3];
fds[0] = s1;
fds[1] = s2;
fds[2] = neighbour_socket;
int p = 0;
int p_flag = 0;
while (1) {
printf("\n nfds = %d , p = %d \n", nfds, p);
char buf_msg[64];
//This is where the error occurs //
rv = select(nfds, &readfds, NULL, NULL, 0);
//This is where the error occurs //
if (rv == -1) {
perror("select"); // error occurred in select()
} else if (rv == 0) {
printf("Timeout occurred! No data after 10.5 seconds.\n");
} else {
// one or both of the descriptors have data
//reading message from server
int select_fd;
for (select_fd = 0; select_fd <= nfds; select_fd++) {
if (FD_ISSET(select_fd, &readfds) != 0) {
if (select_fd == s1) {
recv_len = 0;
recv_len = recv(s1, buf_msg, 34, 0);
if (recv_len < 0) {
perror("recv");
exit(1);
}
buf_msg[recv_len] = '\0';
printf("\nreceived from server = %s\n", buf_msg);
//send to neighbour
int sc3;
sc3 = connect(neighbour_socket, (struct sockaddr *) &neighbour, sizeof(neighbour));
if (sc3 < 0) {
perror("connect:");
exit(sc3);
}
str = malloc(1);
strcpy(str, buf_msg);
send_len = send(neighbour_socket, str, strlen(str), 0);
printf("\n send - len - s1 - %d\n", send_len);
if (send_len != strlen(str)) {
perror("send");
exit(1);
}
start_flag = 1;
//FD_CLR(s1, &readfds);
printf("\ncrossed server\n");
} else if (select_fd == s2) {
int list_len = sizeof incoming;
printf("\ninside client\n");
printf("\nWaiting for accept in S2\n");
if (p_flag == 0) {
p_flag = 1;
p = accept(s2, (struct sockaddr *) &incoming, &list_len);
printf("\nConnection accepted in S2\n");
if (p < 0) {
perror("bind:");
exit(rc);
}
}
nfds = MAX(nfds, p);
recv_len = 0;
buf_msg[recv_len] = '\0';
recv_len = recv(p, buf_msg, 34, 0);
if (recv_len < 0) {
perror("recv");
exit(1);
}
buf_msg[recv_len] = '\0';
printf("\nreceived from client = %s\n", buf_msg);
//send to neighbour
//if(start_id!=1){
int sc3;
sc3 = connect(neighbour_socket, (struct sockaddr *) &neighbour, sizeof(neighbour));
if (sc3 < 0) {
perror("connect:");
//exit(sc3);
}
//}
str = malloc(1);
strcpy(str, buf_msg);
send_len = send(neighbour_socket, str, strlen(str), 0);
printf("\n send - len - s2 - %d\n", send_len);
if (send_len != strlen(str)) {
perror("send");
exit(1);
}
} else if (select_fd == neighbour_socket) {
printf("\ncomes in\n");
} else if (select_fd == p && p != 0) {
int list_len = sizeof incoming;
printf("\ninside p\n");
recv_len = 0;
buf_msg[recv_len] = '\0';
printf("\nwaiting at recv in P\n");
recv_len = recv(p, buf_msg, 34, 0);
printf("\ncrossed at recv in P\n");
if (recv_len < 0) {
perror("recv");
exit(1);
}
buf_msg[recv_len] = '\0';
printf("\nreceived from client = %s\n", buf_msg);
//send to neighbour
str = malloc(1);
strcpy(str, buf_msg);
send_len = send(neighbour_socket, str, strlen(str), 0);
printf("\n send - len - neighbour - %d\n", send_len);
if (send_len != strlen(str)) {
perror("send");
exit(1);
}
}
}
}
FD_ZERO(&readfds);
//FD_SET(neighbour_socket,&readfds);
FD_SET(s1, &readfds);
FD_SET(neighbour_socket, &readfds);
if (p_flag == 1) {
printf("\nsetting P\n");
FD_SET(p, &readfds);
FD_SET(s2, &readfds);
p_flag = 0;
} else {
printf("\nNot setting P\n");
FD_SET(s2, &readfds);
}
}
}
close(s1);
close(s2);
}
提前致謝。
要select
的第一個參數必須是最大文件描述符加一個 。 就我在發布的大量代碼中所知,您忘記了“加一”。
我相信Mat已經找到了潛在的問題 。 但我認為這里存在一個更大的問題:
int send_len;
char *str=malloc(1);
sprintf(str,"%d",peer_port);
printf("\nport-here=%s\n",str);
您已經通過sprintf(3)
調用破壞了堆。 可能不是您覆蓋的重要數據,也許malloc(3)
實際上不會分配一個字節 ,但這是一個錯誤的假設。 您需要為端口號分配至少六個字節:五個用於65535
的數字,一個用於尾隨ASCII NUL
\\0
字節。
buf[recv_len] = '\0';
char *temp_port;
//printf("\n-%s\n",buf);
if ( !strcmp("close", buf) )
printf("%s",buf);
//break;
else{
char *temp_buffer=malloc(1);
char *id=malloc(100);
char *pp=malloc(1);
strcpy(temp_buffer,buf);
在前面的選擇中,您已將\\0
存儲到buf
的末尾,因此大概是在處理某種類型的字符串。 但是在幾行中,您分配了一個字節,然后繼續將buf
的內容復制到該字節中。 ASCII NUL
將完全使用該字節,而您收到的字符串將不留任何空間。 但是strcpy(3)
不能那樣工作-它會將buf
的內容復制到以單個字節開頭的'\\0'
字符到內存中,直到該'\\0'
字符為止。 您再次破壞了堆。 但是這一次它可以覆蓋超過五個字節的所有字節,並且全部在遠程對等方的控制下。
堆溢出非常危險 。 我發現有350多個程序中的可利用錯誤的引用,這些錯誤直接源自我來自“ 常見漏洞和披露”項目的舊存檔中的堆溢出。
在解決這些問題之前,請勿在可公開訪問的計算機上部署該程序。 它代表了一個重大的安全漏洞。 查找malloc(1)
每個實例,並將其替換為必須分配的正確內存量。 完成此操作后,請以MALLOC_CHECK_=1
或在valgrind(1)
控制下運行程序,以幫助您發現更多的內存分配問題。
您是否考慮過使用poll()而不是select()? 它可以輕松調試並優雅地擴展到所需的任何數量。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.