问题
I'm trying to implement select(..) on the client side with creating multiple sockets apart from the TCP socket to recv(..) from the server. I want to receive the data on different recv(..) of different sockets created using select(..). The code doesn't seem to function as expected. Please help. Thanks!
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
int count, createsocket, chunks, newsocket[5], i;
int bufsize = 2048;
char *buffer = malloc(bufsize);
char fname[256];
struct sockaddr_in address;
fd_set master;
fd_set read_fds;
int fdmax, j;
FD_ZERO(&master);
FD_ZERO(&read_fds);
if((createsocket = socket(AF_INET, SOCK_STREAM, 0)) > 0)
{
printf("Socket created.\n");
}
address.sin_family = AF_INET;
address.sin_port = htons(15001);
inet_pton(AF_INET, argv[1], &address.sin_addr);
if(connect(createsocket, (struct sockaddr*)&address, sizeof(address)) == 0)
{
printf("Connected to server %s\n",argv[1]);
}
printf("Enter the file name to download\n");
scanf("%s",fname);
send(createsocket, fname, sizeof(fname), 0);
// printf("Enter the chunks of file to receive");
printf("waiting to receive the file from server..\n");
//code to create a new socket based on the number of chunks required
for(i=0;i<4;i++)
{
if((newsocket[i] = socket(AF_INET, SOCK_STREAM, 0)) > 0)
{
printf("new Socket %d created.\n", i);
}
}
FD_SET(createsocket, &master);
fdmax = createsocket;
for(;;)
{
read_fds = master;
if(select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1){
perror("select");
exit(2);
}
for(i=0; i<=fdmax; i++){
if(FD_ISSET(i, &read_fds)) {
if(i == createsocket) {
printf("something is happening..\n");
if(newsocket[i] == -1){
printf("socket %d\n",i);
} else {
FD_SET(newsocket[i], &master);
if(newsocket[i] > fdmax) {
fdmax = newsocket[i];
}
printf("still something is going on..\n");
}
} else {
printf("Doing something..\n");
for(j = 0; j <= fdmax; j++) {
if(FD_ISSET(j, &master)) {
if(j!= createsocket && j!= i) {
if((count = recv(createsocket, buffer, bufsize, 0)) > 0) {
perror("recv");
} else {
write(1, buffer, count);
}
}
}
}
}
}
}
}
// while((count = recv(createsocket, buffer, bufsize, 0)) > 0)
// write(1, buffer, count);
printf("EOF.\n");
for(i=0;i<4;i++)
{
close(newsocket[i]);
}
return close(createsocket);
}
回答1:
Two quick comments:
First, we would need to set the file descriptor (fd) -- as many fds, as the application logic demands -- before calling select() everytime in the while loop. We should also set the fd_set to zeros before doing the above step. This is because when select returns, it will return the same fd_set but it will set only those that have the event set. So, one way to do this is to start with a clean state and then set all the fds that we are interested in. Something like this:
FD_ZERO(&read_fd_set);
FD_SET(createsocket, &master); // We should do this for all connections
if(select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1){
Second, you are creating all the other sockets (besides createsocket socket), you open a TCP socket and yet do nothing with it. If it is a client, at the very least, we would have to call connect(). Without setting up an explicit connection, we cannot do anything useful with TCP sockets.
So, high-level comment is that if you want to have N client sockets, then open N sockets and connect all sockets to the server. Next, pass all the N fds to the select() (everytime you call select()) and do this in a loop.
回答2:
The problem is that you are calling recv()
on sockets which aren't ready for reading. That's what select()
is for, to tell you which sockets are ready for reading. Your logic that calls recv()
processes the entire collection of fds, not just the fds in the ready-set.
来源:https://stackoverflow.com/questions/19062754/using-select-on-client