2010-06-27 55 views
1

我有这个编,只是一个简单的服务器和客户端连接的骨架。我会让它聊天。 (不介意线程FUNC和信号..)linux套接字:客户端之前服务器退出

服务器:

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <errno.h> 
#include <time.h> 
#include <string.h> 
#include <signal.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netdb.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <pthread.h> 


#define BUFFERSIZE 512 
#define TIMESIZE 32 
#define QUIT "!quit" 


// thread pou diavazei 
void *readthread(void *argp); 
// katharizei ligo prin kleisei to programma 
void progreset(); 
// kleinei to prog me ctrl-c 
void sigexit(); 


int sock, endchat; 
char username1[50]; 
pthread_t thrread; 


int main(int argc, char** argv) { 
    int port, s; 
    char username[50]; 
    struct sockaddr_in server, client; 
    struct sockaddr *serverptr, *clientptr; 
    unsigned int clientlen; 
    char buf[BUFFERSIZE]; 
    int len; 
    time_t sec; 
    char timestr[TIMESIZE]; 


    signal(SIGPIPE, SIG_IGN); 
    signal(SIGINT, sigexit); 


    if (argc != 3) { 
     printf("Error: Wrong arguments\n"); 
     printf("Usage: %s <username> <port>\n", argv[0]); 
     return -1; 
    } 

    strcpy(username, argv[1]); 
    port = atoi(argv[2]); 

    // ftiaxno to socket 
    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 
     perror("Failed to create socket"); 
     return -1; 
    } 
    server.sin_family = AF_INET; 
    server.sin_addr.s_addr = htonl(INADDR_ANY); 
    server.sin_port = htons((short)port); 
    if (bind(s, (struct sockaddr *)&server, sizeof(server)) < 0) { 
     perror("Failed to bind socket"); 
     return -1; 
    } 

    if (listen(s, 5) != 0) { 
     perror("Error in listen()"); 
     return -1; 
    } 

    clientptr = (struct sockaddr *)&client; 
    clientlen = sizeof(client); 

    // perimeno sindesi apo ton pelati 
    printf("Accepting connections on port %d..\n", port); 
    if ((sock = accept(s, clientptr, &clientlen)) < 0) { 
     perror("Error in accept()"); 
     return -1; 
    } 

    // pairno to ip tou pelati 
    if (getpeername(sock, (struct sockaddr *)&client, &clientlen) < 0) { 
     printf("Accepted connection\n"); 
    } else { 
     printf("Accepted connection from %s\n", inet_ntoa(client.sin_addr)); 
    } 

    // stelno kai pairno ta usernames 
    bzero(buf, sizeof(buf)); 
    strcpy(buf, username); 
    if (write(sock, buf, sizeof(buf)) < 0) { 
     perror("write1"); 
     return -1; 
    } 

    bzero(buf, sizeof(buf)); 
    if (read(sock, buf, sizeof(buf)) < 0) { 
     perror("read1"); 
     return -1; 
    } 
    strcpy(username1, buf); 

    printf("Chatting with %s..\n\n", username1); 








    progreset(); 
    return 0; 
} 


void *readthread(void *argp) { 
    char buf[BUFFERSIZE]; 
    char timestr[TIMESIZE]; 
    int len; 
    time_t sec; 
    struct tm *timeinfo; 


    while (1) { 

    } 



    endchat = 1; 
    pthread_exit(0); 
} 


void progreset() { 
    printf("\nExiting..\n"); 
    close(sock); 
} 


void sigexit() { 
    printf("test\n"); 
    close(sock); 
    signal(SIGINT, SIG_DFL); 
    kill(getpid(),SIGINT); 
    printf("ok\n"); 

    exit(0); 
} 

客户

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <errno.h> 
#include <string.h> 
#include <signal.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netdb.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <pthread.h> 


#define BUFFERSIZE 512 
#define TIMESIZE 32 
#define QUIT "!quit" 


// thread pou diavazei 
void *readthread(void *argp); 
// katharizei ligo prin kleisei to programma 
void progreset(); 
// kleinei to prog me ctrl-c 
void sigexit(); 


int sock, endchat; 
char username1[50]; 
pthread_t thrread; 


int main(int argc, char** argv) { 
    int port; 
    char username[50]; 
    struct sockaddr_in server, client; 
    struct sockaddr *serverptr, *clientptr; 
    unsigned int serverlen; 
    struct hostent *rem; 
    char buf[BUFFERSIZE]; 
    int len; 
    time_t sec; 
    char timestr[TIMESIZE]; 


    signal(SIGPIPE, SIG_IGN); 
    signal(SIGINT, sigexit); 


    if (argc != 4) { 
     printf("Error: Wrong arguments\n"); 
     printf("Usage: %s <username> <ip address> <port>\n", argv[0]); 
     return -1; 
    } 

    strcpy(username, argv[1]); 
    port = atoi(argv[3]); 

    // ftiaxno to socket 
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 
     perror("Failed to create socket"); 
     return -1; 
    } 
    rem = gethostbyname(argv[2]); 
    server.sin_family = AF_INET; 
    bcopy((char*)rem->h_addr, (char*)&server.sin_addr, rem->h_length); 
    server.sin_port = htons((short)port); 
    serverptr = (struct sockaddr *)&server; 
    serverlen = sizeof(server); 

    // kano connect me to server 
    if (connect(sock, serverptr, serverlen) < 0) { 
     perror("Failed to connect"); 
     return -1; 
    } 

    // pairno kai stelno ta usernames 
    bzero(buf, sizeof(buf)); 
    if (read(sock, buf, sizeof(buf)) < 0) { 
     perror("read1"); 
     return -1; 
    } 
    strcpy(username1, buf); 

    bzero(buf, sizeof(buf)); 
    strcpy(buf, username); 
    if (write(sock, buf, sizeof(buf)) < 0) { 
     perror("write1"); 
     return -1; 
    } 

    printf("Chatting with %s..\n\n", username1); 







    sleep(1); 










    progreset(); 
    return 0; 
} 


void *readthread(void *argp) { 
    char buf[BUFFERSIZE]; 
    char timestr[TIMESIZE]; 
    int len; 
    time_t sec; 
    struct tm *timeinfo; 

    while (1) { 
    } 
    endchat = 1; 
    pthread_exit(0); 
} 


void progreset() { 
    printf("\nExiting..\n"); 
    close(sock); 
} 


void sigexit() { 
    printf("test\n"); 
    close(sock); 
    signal(SIGINT, SIG_DFL); 
    kill(getpid(),SIGINT); 
    printf("ok\n"); 

    exit(0); 
} 

在main()FUNC按键,服务器只是等待连接,然后退出。客户端在连接睡眠1秒后,然后结束。

当我运行这一点,像./server服务器1234 然后./client客户端本地主机1234 都正常退出,但是当我第二次运行该服务器,它说未能绑定套接字:已在使用中的地址。

有什么不对? 服务器必须在客户端之后始终退出吗?

奖金问:我想每个程序有两个线程,一个读取一个写入。他们可以在同一个插座上操作吗?

非常感谢你

+0

您是否删除了.sock文件? – 2010-06-27 16:47:07

+0

.sock ??我没有.sock文件 – pvinis 2010-06-27 16:51:58

+0

也许我错了,但是当你创建一个套接字,并且你把它叫做MYSOCK时,它会在你的目录MYSOCK.sock中创建一个文件(如果你没有指定)。如果您发现将其删除,然后重试。如果你找不到我错了! 编辑可能我错了,因为我使用AF_UNIX套接字。对不起 – 2010-06-27 16:55:10

回答

1

请确保在退出之前在插座上调用closesocket(s)。
也请在打开之前尝试使用setsockopt SO_REUSEADDR。

Here是Linux Sockets上的一个很好的教程。

当然,如果你发布了一些代码,它会使它更容易。

您可以在同一个套接字上读写。

我怀疑你得到“Address in use error”(EADDRINUSE)
你可以使用bind API函数将一个地址(一个接口和一个端口)绑定到一个套接字端点上。您可以在服务器设置中使用此功能来限制传入连接可能的接口。您也可以在客户端设置中使用此功能来限制应该用于传出连接的接口。
绑定的最常见用途是将端口号与服务器相关联,并使用通配符地址(INADDR_ANY),该地址允许任何接口用于传入连接。
绑定常遇到的问题是试图绑定已经在使用的端口。缺点是没有活动的套接字可能存在,但绑定到端口仍然被禁止(绑定返回EADDRINUSE),这是由TCP套接字TIME_WAIT状态引起的。这个状态在关闭后会保持一个插槽两到四分钟。
TIME_WAIT状态退出后,套接字被删除,并且地址可以被反弹而没有问题。
等待TIME_WAIT完成可能很烦人,特别是如果您正在开发套接字服务器,并且您需要停止服务器进行更改并重新启动它。幸运的是,有一种解决TIME_WAIT状态的方法。您可以将SO_REUSEADDR套接字选项应用于套接字,以便可以立即重新使用该端口。 在绑定地址之前,我使用SO_REUSEADDR选项调用setsockopt。要启用地址重用,我将整数参数(on)设置为1(否则,您可以将其设置为0以禁用地址重用)。

使用SO_REUSEADDR套接字选项

int sock, ret, on; 
struct sockaddr_in servaddr; 

/* Create a new stream (TCP) socket */ 
sock = socket(AF_INET, SOCK_STREAM, 0): 

/* Enable address reuse */ 
on = 1; 
ret = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 

/* Allow connections to port 8080 from any available interface */ 
memset(&servaddr, 0, sizeof(servaddr)); 
servaddr.sin_family = AF_INET; 
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 
servaddr.sin_port = htons(45000); 

/* Bind to the address (interface/port) */ 
ret = bind(sock, (struct sockaddr *)&servaddr, sizeof(servaddr)); 

后您已应用SO_REUSEADDR套接字选项避免“地址在使用”错误,绑定API函数总是允许地址的立即重用。

+0

我是否在绑定之前放置这个? – pvinis 2010-06-27 22:06:31

+0

@pvinis _我更新了我的帖子,告诉我如何使用SO_REUSEADDR – 2010-06-27 22:28:55

+0

非常感谢!我注意到几秒钟后端口是空闲的,但我不知道TIME_WAIT。 setsockopt和SO_REUSEADDR解决了我的问题。 – pvinis 2010-06-29 09:04:47

相关问题