2012-04-27 145 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將錯誤代碼轉換爲人類可讀的消息。