2012-04-27 111 views
3

以下来自http://www.thomasstover.com/uds.html的unix域套接字客户端和服务器示例在我的slackware linux框上无法正常工作。我得到这样的输出:Linux上的unix域套接字?

$ ./server1 
$ 

$ ./client1 
MESSAGE FROM SERVER: hello from a client 

我预计服务器打印消息hello从客户端和客户端从服务器打印打招呼。

我的操作系统和编译器是这些:

$ uname -a                          
Linux temeraire 2.6.37.6-smp #2 SMP Sat Apr 9 23:39:07 CDT 2011 i686 Intel(R) Xeon(R) CPU   E3110 @ 3.00GHz Ge 
nuineIntel GNU/Linux 
$ gcc -v 
Reading specs from /usr/lib/gcc/i486-slackware-linux/4.5.2/specs 
COLLECT_GCC=gcc 
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/i486-slackware-linux/4.5.2/lto-wrapper 
Target: i486-slackware-linux 
Configured with: ../gcc-4.5.2/configure --prefix=/usr --libdir=/usr/lib --mandir=/usr/man --infodir=/usr/info --enable- 
shared --enable-bootstrap --enable-languages=ada,c,c++,fortran,java,objc,lto --enable-threads=posix --enable-checking=r 
elease --with-system-zlib --with-python-dir=/lib/python2.6/site-packages --disable-libunwind-exceptions --enable-__cxa_ 
atexit --enable-libssp --enable-lto --with-gnu-ld --verbose --with-arch=i486 --target=i486-slackware-linux --build=i486 
-slackware-linux --host=i486-slackware-linux 
Thread model: posix 
gcc version 4.5.2 (GCC) 

server.c:

#include <stdio.h> 
#include <sys/socket.h> 
#include <sys/un.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <string.h> 

int connection_handler(int connection_fd) 
{ 
int nbytes; 
char buffer[256]; 

nbytes = read(connection_fd, buffer, 256); 
buffer[nbytes] = 0; 

printf("MESSAGE FROM CLIENT: %s\n", buffer); 
nbytes = snprintf(buffer, 256, "hello from the server"); 
write(connection_fd, buffer, nbytes); 

close(connection_fd); 
return 0; 
} 

int main(void) 
{ 
struct sockaddr_un address; 
int socket_fd, connection_fd; 
socklen_t address_length; 
pid_t child; 

socket_fd = socket(PF_UNIX, SOCK_STREAM, 0); 
if(socket_fd < 0) 
{ 
    printf("socket() failed\n"); 
    return 1; 
} 

unlink("./demo_socket"); 

/* start with a clean address structure */ 
memset(&address, 0, sizeof(struct sockaddr_un)); 

address.sun_family = AF_UNIX; 
snprintf(address.sun_path, UNIX_PATH_MAX, "./demo_socket"); 

if(bind(socket_fd, 
     (struct sockaddr *) &address, 
     sizeof(struct sockaddr_un)) != 0) 
{ 
    printf("bind() failed\n"); 
    return 1; 
} 

if(listen(socket_fd, 5) != 0) 
{ 
    printf("listen() failed\n"); 
    return 1; 
} 

while((connection_fd = accept(socket_fd, 
           (struct sockaddr *) &address, 
           &address_length)) > -1) 
{ 
    child = fork(); 
    if(child == 0) 
    { 
    /* now inside newly created connection handling process */ 
    return connection_handler(connection_fd); 
    } 

    /* still inside server process */ 
    close(connection_fd); 
} 

close(socket_fd); 
unlink("./demo_socket"); 
return 0; 
} 

client.c:

#include <stdio.h> 
#include <sys/socket.h> 
#include <sys/un.h> 
#include <unistd.h> 
#include <string.h> 

int main(void) 
{ 
struct sockaddr_un address; 
int socket_fd, nbytes; 
char buffer[256]; 

socket_fd = socket(PF_UNIX, SOCK_STREAM, 0); 
if(socket_fd < 0) 
{ 
    printf("socket() failed\n"); 
    return 1; 
} 

/* start with a clean address structure */ 
memset(&address, 0, sizeof(struct sockaddr_un)); 

address.sun_family = AF_UNIX; 
snprintf(address.sun_path, UNIX_PATH_MAX, "./demo_socket"); 

if(connect(socket_fd, 
      (struct sockaddr *) &address, 
      sizeof(struct sockaddr_un)) != 0) 
{ 
    printf("connect() failed\n"); 
    return 1; 
} 

nbytes = snprintf(buffer, 256, "hello from a client"); 
write(socket_fd, buffer, nbytes); 

nbytes = read(socket_fd, buffer, 256); 
buffer[nbytes] = 0; 

printf("MESSAGE FROM SERVER: %s\n", buffer); 

close(socket_fd); 

return 0; 
} 
+1

为什么不在调试器中运行程序并告诉我们你找到了什么? – 2012-04-27 23:18:30

+0

它适合我。你使用的是什么操作系统和编译器? ('uname -a','gcc -v') – jedwards 2012-04-27 23:23:59

+1

我将我的编译器和uname -a添加到了问题中。 @约翰好主意。 – selden 2012-04-27 23:50:25

回答

5

由于Dietrich Epp mentioned,你无法初始化在服务器代码中传递给acceptaddress_length参数。根据man page,这个参数既是一个输入参数,也是一个输出参数:在输入时,告诉它你的地址结构有多大(所以当告诉你连接客户端的地址时它不知道写入内存越界),并在输出它告诉你实际地址有多大。

要解决该问题,请在致电accept之前初始化address_lengthsizeof(address)。您也应该为每次致电accept都这样做,因为该变量可以被修改。例如:

while(1) 
{ 
    address_length = sizeof(address); 
    if((connection_fd = accept(..., &address_length)) == -1) 
    { 
    printf("accept error: %s\n", strerror(errno)); 
    break; 
    } 
    ... 
} 

我能够重现你的问题被明确初始化address_length到的无效值(sockaddr_t)-1,造成accept失败与错误EINVAL(无效参数),但奇怪的是它没有失败直到客户端尝试连接之后,当客户端尝试连接时,它实际上成功了,但是当它尝试写入套接字时,失败并返回ECONNRESET(“通过对等方重置连接”)

另一个关键点是你应该总是检查你的返回值,在处理套接字代码时,有很多要点失败,所以它是迂腐的。如果系统调用失败,它将返回-1并将errno设置为适当的值。正如我在上面的例子中所做的那样,您可以使用strerror function将错误代码转换为人类可读的消息。