加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

如何知道客户端是否在套接字中终止

发布时间:2020-12-16 03:12:44 所属栏目:百科 来源:网络整理
导读:假设我写了这个代码后有一个连接的socket if ((sd = accept(socket_d,(struct sockaddr *)client_addr,alen)) 0){ perror("accept failedn"); exit(1);} 我如何知道客户端已退出的服务器端. 我的整个程序实际上做了以下.. 接受来自客户端的连接 启动从该特
假设我写了这个代码后有一个连接的socket
if ((sd = accept(socket_d,(struct sockaddr *)&client_addr,&alen)) < 0)
{
    perror("accept failedn");
    exit(1);
}

我如何知道客户端已退出的服务器端.

我的整个程序实际上做了以下..

>接受来自客户端的连接
>启动从该特定客户端读取消息的新线程,然后将此消息广播到所有连接的客户端.

如果你想看到整个代码…在这整个代码.我也遇到一个问题,每当我用Ctrl C杀死一个客户端,我的服务器突然终止..如果有人可以建议什么问题,这将是很好的

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

/*CONSTANTS*/
#define DEFAULT_PORT 10000 
#define LISTEN_QUEUE_LIMIT 6
#define TOTAL_CLIENTS 10
#define CHAR_BUFFER 256

/*GLOBAL VARIABLE*/
int current_client = 0;
int connected_clients[TOTAL_CLIENTS];
extern int errno;

void *client_handler(void * socket_d);

int main(int argc,char *argv[])
{
    struct sockaddr_in server_addr;/* structure to hold server's address*/
    int    socket_d;             /* listening socket descriptor       */
    int    port;           /* protocol port number              */
    int    option_value;   /* needed for setsockopt             */
    pthread_t tid[TOTAL_CLIENTS];
    port = (argc > 1)?atoi(argv[1]):DEFAULT_PORT;

    /* Socket Server address structure */
    memset((char *)&server_addr,sizeof(server_addr)); 
    server_addr.sin_family = AF_INET;               /* set family to Internet */
    server_addr.sin_addr.s_addr = INADDR_ANY;       /* set the local IP address */
    server_addr.sin_port = htons((u_short)port);    /* Set port */

    /* Create socket */
    if ( (socket_d = socket(PF_INET,SOCK_STREAM,0)) < 0) {
        fprintf(stderr,"socket creation failedn");
        exit(1);
    }

    /* Make listening socket's port reusable */
    if (setsockopt(socket_d,SOL_SOCKET,SO_REUSEADDR,(char *)&option_value,sizeof(option_value)) < 0) {
        fprintf(stderr,"setsockopt failuren");
        exit(1);
    }

    /* Bind a local address to the socket */
    if (bind(socket_d,(struct sockaddr *)&server_addr,sizeof(server_addr)) < 0) {
        fprintf(stderr,"bind failedn");
        exit(1);
    }

    /* Specify size of request queue */
    if (listen(socket_d,LISTEN_QUEUE_LIMIT) < 0) {
        fprintf(stderr,"listen failedn");
        exit(1);
    }

    memset(connected_clients,sizeof(int)*TOTAL_CLIENTS);

    for (;;)
    {
        struct sockaddr_in client_addr;    /* structure to hold client's address*/
        int    alen = sizeof(client_addr); /* length of address                 */
        int    sd;                /* connected socket descriptor */

        if ((sd = accept(socket_d,&alen)) < 0)
        {
            perror("accept failedn");
            exit(1);
        }
        else printf("n I got a connection from (%s,%d)n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));

        if (pthread_create(&tid[current_client],NULL,(void *)client_handler,(void *)sd) != 0)
        {
            perror("pthread_create error");
            continue;
        }
        connected_clients[current_client]=sd;
        current_client++; /*Incrementing Client number*/
    }

    return 0;
}

void *client_handler(void *connected_socket)
{
    int sd;
    sd = (int)connected_socket;
    for ( ; ; ) 
    {
        ssize_t n;
        char buffer[CHAR_BUFFER];
        for ( ; ; )
        {
            if (n = read(sd,buffer,sizeof(char)*CHAR_BUFFER) == -1)
            {
                perror("Error reading from client");
                pthread_exit(1);
            }
            int i=0;
            for (i=0;i<current_client;i++)
            {
                if (write(connected_clients[i],sizeof(char)*CHAR_BUFFER) == -1)
                    perror("Error sending messages to a client while multicasting");
            }
        }
    }
}

我的客户端是(Maye在回答我的问题时无关紧要)

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 
#include <string.h>
#include <stdlib.h>

void error(char *msg)
{
    perror(msg);
    exit(0);
}

void *listen_for_message(void * fd)
{
    int sockfd = (int)fd;
    int n;
    char buffer[256];
    bzero(buffer,256);
    printf("YOUR MESSAGE: ");
    fflush(stdout);
    while (1)
    {
        n = read(sockfd,256);
        if (n < 0) 
            error("ERROR reading from socket");
        if (n == 0) pthread_exit(1);
        printf("nMESSAGE BROADCAST: %sYOUR MESSAGE: ",buffer);
        fflush(stdout);
    }
}

int main(int argc,char *argv[])
{
    int sockfd,portno,n;
    struct sockaddr_in serv_addr;
    struct hostent *server;
    pthread_t read_message;
    char buffer[256];
    if (argc < 3) {
        fprintf(stderr,"usage %s hostname portn",argv[0]);
        exit(0);
    }
    portno = atoi(argv[2]);
    sockfd = socket(AF_INET,0);
    if (sockfd < 0) 
        error("ERROR opening socket");
    server = gethostbyname(argv[1]);
    if (server == NULL) {
        fprintf(stderr,"ERROR,no such hostn");
        exit(0);
    }
    bzero((char *) &serv_addr,sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr,(char *)&serv_addr.sin_addr.s_addr,server->h_length);
    serv_addr.sin_port = htons(portno);
    if (connect(sockfd,&serv_addr,sizeof(serv_addr)) < 0) 
        error("ERROR connecting");
    bzero(buffer,256);
    if (pthread_create(&read_message,(void *)listen_for_message,(void *)sockfd) !=0 )
    {
        perror("error creating thread");
    }
    while (1)
    {
        fgets(buffer,255,stdin);
        n = write(sockfd,256);
        if (n < 0) 
            error("ERROR writing to socket");
        bzero(buffer,256);
    }
    return 0;
}

解决方法

接受连接后,在特殊情况下,套接字上的recv()将返回0或-1.

摘自recv(3) man page:

Upon successful completion,recv()
shall return the length of the message
in bytes. If no messages are available
to be received and the peer has
performed an orderly shutdown,recv()
shall return 0. Otherwise,-1 shall be
returned and errno set to indicate the
error.

所以,如果您的客户端正常退出,您将在某个时刻从recv()获取0.如果连接丢失了,你也可能得到-1,并检查相应的errno会告诉你连接是否丢失了一些其他错误.详见recv(3) man page.

编辑:

我看到你正在使用read().尽管如此,与recv()相同的规则也适用.

尝试向客户端写()时,您的服务器也可能会失败.如果您的客户端断开连接,write()将返回-1,并且可能将errno设置为EPIPE.此外,如果您不阻止/忽略此信号,SIGPIPE信号将发送给您进程并杀死他.而且您不会看到,这就是为什么当客户端按Ctrl-C时,您的服务器会终止. Ctrl-C终止客户端,因此关闭客户端套接字,使您的服务器的write()失败.

请参阅mark4o的答案,详细说明还有什么可能出错.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读