【发布时间】:2015-03-01 15:41:31
【问题描述】:
这是一个带有 select()` 的服务器实现和一个简单的客户端。它不是主应用程序,而是一个示例,可能无法运行。重要的是来自服务器的无限循环。
问题出现在这里:客户端发送一个(正确的)消息,从服务器接收一个(正确的)答案,然后,当他发送另一个消息时,它收到错误:写入():错误的文件描述符。
我重新检查了服务器,但他没有关闭它。我怀疑问题出在 select() 或服务器架构中。
编辑: 如果相关,我会在 127.0.0.1 上测试我的应用。
服务器
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>
#define PORT 2728
extern int errno;
/* converting client address int char* */
char * conv_addr (struct sockaddr_in address)
{
static char str[25];
char port[7];
strcpy (str, inet_ntoa (address.sin_addr));
bzero (port, 7);
sprintf (port, ":%d", ntohs (address.sin_port));
strcat (str, port);
return (str);
}
int main ()
{
struct sockaddr_in server;
struct sockaddr_in from;
fd_set readfds; //clients which are ready to write
fd_set actfds; //active clients
struct timeval tv;
int sd, client;
int optval=1;
int fd;
int nfds; //max number of descriptors
int len;
if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
{
perror ("[server] Error:socket().\n");
return errno;
}
/*SO_REUSEADDR option*/
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR,&optval,sizeof(optval));
bzero (&server, sizeof (server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl (INADDR_ANY);
server.sin_port = htons (PORT);
if (bind (sd, (struct sockaddr *) &server, sizeof (struct sockaddr)) == -1)
{
perror ("[server] Error:bind().\n");
return errno;
}
if (listen (sd, 5) == -1)
{
perror ("[server] Error:listen().\n");
return errno;
}
FD_ZERO (&actfds);
FD_SET (sd, &actfds);
tv.tv_sec = 1;
tv.tv_usec = 0;
nfds = sd;
printf ("[server] Waiting at port %d...\n", PORT);
fflush (stdout);
/* serving clients... */
while (1)
{
bcopy ((char *) &actfds, (char *) &readfds, sizeof (readfds));
if (select (nfds+1, &readfds, NULL, NULL, &tv) < 0)
{
perror ("[server] Error:select().\n");
return errno;
}
if (FD_ISSET (sd, &readfds))
{
/* preparing client structure */
len = sizeof (from);
bzero (&from, sizeof (from));
client = accept (sd, (struct sockaddr *) &from, &len);
if (client < 0)
{
perror ("[server] Error:accept()\n");
continue;
}
if (nfds < client) /* adjusting max value */
nfds = client;
FD_SET (client, &actfds);
printf("[server] Client with %d descriptor and %s address connected.\n",client, conv_addr (from));
fflush (stdout);
}
/* checking if any client is ready so 'speak' */
for (fd = 0; fd <= nfds; fd++)
{
if (fd != sd && FD_ISSET (fd, &readfds))
{
//receive message from client
//do something
//sent back result
}
}
/* for */
} /* while */
} /* main */
客户
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <string.h>
extern int errno;
int port;
int main (int argc, char *argv[])
{
int sd;
struct sockaddr_in server;
char msg[100];
if (argc != 3)
{
printf ("[client] Sintax: %s <server_address> <port>\n", argv[0]);
return -1;
}
port = atoi (argv[2]);
if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
{
perror ("[client] Error:socket().\n");
return errno;
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(argv[1]);
server.sin_port = htons (port);
if (connect (sd, (struct sockaddr *) &server,sizeof (struct sockaddr)) == -1)
{
perror ("[client]Error: connect().\n");
return errno;
}
while(1)/*meaning untill user doesn't close the client*/)
{
//here are the functions used to communicate with server. Same in server.
if (write (sd, msg, 100) <= 0)
{
perror ("[client]Error:write().\n");
return errno;
}
if (read (sd, msg, 100) < 0)
{
perror ("[client]Error:read().\n");
return errno;
}
}//while
close (sd);
}//main
【问题讨论】:
-
这一行:'extern int errno;'在errno.h文件中,这里不需要再定义了。
-
您必须关闭套接字。这是真正的代码吗?你确定关闭不在循环内吗?
-
您需要(最终)关闭原始套接字和由 accept() 返回的套接字。这一行:'while(/*user doesn't close client*/)' 应该是:while(1) ?*user doesn't close client*/
-
我强烈建议您在通过 TCP/IP 套接字进行通信时使用 send() 和 recv(),而不是使用 write() 和 read()
-
@user3629249 你强烈建议为什么?