複数のクライアントを受け入れるサーバー プログラムを作成するという課題があります。私は C 言語で書いており、select() ステートメントを使用してこれを達成しようとしています。コンパイルはできますが、telnet で接続するたびに、「Socket operation on non-socket error.」というメッセージが表示されます。エラーについて調べてみましたが、あまり役立つものは見つかりませんでした。任意の支援をいただければ幸いです。
私のサーバーの出力は次のとおりです。
$ ./assign2 33333
Waiting for connection...
fd is 0
EchoServ recv error: Socket operation on non-socket
fd is 1
EchoServ recv error: Socket operation on non-socket
EchoServ recv error: Socket operation on non-socket
telnet の出力は次のとおりです。
$ telnet localhost 33333
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
Welcome to EchoServ chat.
私のサーバーコード:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define PORT 50000
main( int argc, char *argv[] )
{
char buf[ BUFSIZ ], /* buffer for incoming data */
*endptr, /* for strtol() */
*message = "Welcome to EchoServ chat. \r\n"; /* welcome message */
int masterSocket, /* main listening socket for server */
newSocket, /* new sockets for connecting clients */
opt = 1, /* for port reuse code */
nBytes, /* # of incoming bytes */
addrlen;
int i,j; /* temp vars */
short int port; /* port number */
fd_set master; /* master file descriptor list */
fd_set temp_fds; /* temp file descriptor list for select() */
int fdmax; /* maximum file descriptor number */
struct sockaddr_in sin;
/* Get port number from the command line, or
set to default port if no arguments were supplied */
if ( argc == 2 ) {
port = strtol(argv[1], &endptr, 0);
if ( *endptr ) {
fprintf(stderr, "EchoServ: Invalid port number.\n");
exit(EXIT_FAILURE);
}
}
else {
port = PORT;
}
FD_ZERO(&master); /* clear the master and temp sets */
FD_ZERO(&temp_fds);
/* Get an internet domain socket */
if ( ( masterSocket = socket( AF_INET, SOCK_STREAM, 0) ) == -1 ) {
perror( "EchoServ socket error" );
exit( 1 );
}
/* Complete the socket structure */
memset( &sin, 0, sizeof(sin) );
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(port);
/* Bind the socket to the port number */
if ( bind( masterSocket, ( struct sockaddr *) &sin, sizeof( sin ) ) == -1) {
perror( "EchoServ bind failed" );
exit( 1 );
}
/* Allow port reuse */
if ( setsockopt( masterSocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof( opt ) ) == -1 ) {
perror( "EchoServ setsockopt error" );
exit(1);
}
/* Listen for clients that want to connect. */
if ( listen( masterSocket, 5 ) == -1 ) {
perror( "EchoServ listen error" );
exit( 1 );
}
/* add masterSocket to the master set */
FD_SET(masterSocket, &master);
/* track largest file descriptor, starting with masterSocket */
fdmax = masterSocket;
/* Wait for a client connection, then accept it. */
puts ( "Waiting for connection..." );
while(1){
temp_fds = master; /* copy master set to temp set */
//addrlen = sizeof(sin);
/* wait for activity on a socket */
if (select(fdmax+1, &temp_fds, NULL, NULL, NULL) == -1) {
perror("EchoServ select error");
exit(1);
}
for ( i = 0; i <= fdmax; i++ ){
printf("fd is %d\n", i); /*debug*/
if ( FD_ISSET( i, &temp_fds ) ){ /* true if file descriptor is in set */
/* accept new connection */
if ( i == masterSocket ){
addrlen = sizeof( sin );
if ( (newSocket = accept( masterSocket, ( struct sockaddr *) &sin, &addrlen )) == -1 )
perror("EchoServ: accept error");
else {
printf("New connection accepted\n"); /*debug*/
FD_SET( newSocket, &master ); /* add new connection to master set */
if ( newSocket > fdmax ) /* update max descriptor */
fdmax = newSocket;
//print details of new connection
printf("New connection on %s:%d, socket fd is %d \n",
inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), newSocket );
//send new connection greeting message
if( send( newSocket, message, strlen( message ), 0) == -1 )
{
perror("EchoServ welcome message error");
}
puts("Welcome message sent successfully");
}
}
}
/* handle incoming data */
else{
if ( ( nBytes = recv( i, buf, sizeof( buf ), 0 ) ) <= 0 ){ /* error or closed connection */
if ( nBytes == 0 ) /* connection closed */
printf( "EchoServ: socket %d closed by client\n", i );
else /* recv error */
perror("EchoServ recv error");
close( i ); /* close socket */
FD_CLR( i, &master ); /* remove from master set */
}
else { /* got some data */
for( j = 0; j <= fdmax; j++ ){
if ( FD_ISSET( j, &master ) ){ /* send data to all sockets */
if( j != i && j != masterSocket ){ /* except self and masterSocket */
if ( send( j, buf, nBytes, 0) == -1)
perror("EchoServ send error");
}
}
}
}
}
}
}
return( 0 );
}
助けてくれてありがとう。