免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2653 | 回复: 4
打印 上一主题 下一主题

多路复用I/O-select- 简单聊天程序 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-07-08 16:07 |只看该作者 |倒序浏览
一个服务器可对应多个客户端,经测试,服务器可以跟多个客户端交互,只是只能输入输出一条信息,希望大侠帮我看看,谢谢
server.c

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

#define MAX_BUF_SIZE 1024
#define MAX_LISTEN 12

int main(int argc, char *argv[])
{
    int sockfd, conn_fd;
    int client_fd[MAX_LISTEN];
    struct sockaddr_in my_addr, client_addr;
    unsigned int backlog, port;
    int sin_size;
    char buf[MAX_BUF_SIZE + 1];
    fd_set rfds;
    struct timeval tv;
    int retval, maxfd = -1;
    int i;

    if (argv[1])
        port = atoi(argv[1]);
    else
        port = 8003;

    if (argv[2])
        backlog = atoi(argv[2]);
    else
        backlog = 12;
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        fprintf(stderr, "socket error!\n");
        exit(1);
    }

    int on = 1;
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
    {
        fprintf(stderr, "setsockopt failed: %s\n", strerror(errno));
        exit(1);
    }

    bzero(&my_addr, sizeof(my_addr));
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(port);
    if (argv[3])
        my_addr.sin_addr.s_addr = inet_addr(argv[3]);
    else
        my_addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
    {
        fprintf(stderr, "bind error!\n");
        exit(1);
    }

    if (listen(sockfd, backlog) == -1)
    {
        fprintf(stderr, "listen error!\n");
        exit(1);
    }
    printf("*****wait new connection to new chat*****\n");

    for (i=0; i<MAX_LISTEN; i++)
        client_fd = -1;
    FD_ZERO(&rfds);
    maxfd = sockfd;

    while (1)
    {
        FD_CLR(sockfd, &rfds);
        FD_SET(sockfd, &rfds);

        tv.tv_sec = 1;
        tv.tv_usec = 0;

        if ((retval = select(maxfd + 1, &rfds, NULL, NULL, &tv)) < 0)
        {
            if (errno == EINTR)
            {
                fprintf(stdout, "closed by singal, continue...\n");
                continue;
            }
            else if (errno == EAGAIN)
            {
                continue;
            }
            else
            {
                fprintf(stderr, "select error!\n");
            }
        }
        else if (retval == 0)
        {
            continue;
        }


        fprintf(stdout, "Be ready, can chat!\n", retval);

        if (FD_ISSET(sockfd, &rfds))
        {
            sin_size = sizeof(struct sockaddr);
            conn_fd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size);
            if (conn_fd < 0)
            {
                if (errno == EINTR)
                    continue;
                else
                {
                    fprintf(stderr, "accept error!\n");
                    exit(1);
                }
            }

            for (i=0; i<MAX_LISTEN; i++)
            {
                if(client_fd != -1)
                    continue;
                client_fd = conn_fd;
                FD_SET(client_fd, &rfds);
                break;
            }
            if (maxfd < conn_fd)
                maxfd = conn_fd;

            printf("Add client socket connection %d to select\n", conn_fd);
        }

        for (i=0; i<MAX_LISTEN; i++)
        {
            if (client_fd == -1)
                continue;
            if (!FD_ISSET(client_fd, &rfds))
                continue;

            bzero(buf, MAX_BUF_SIZE + 1);
            sin_size = recv(client_fd, buf, MAX_BUF_SIZE, 0);
            if (sin_size > 1)
            {
                printf("receive message successfully: [%s]\ntotal %d bytes\n", buf, sin_size);
            }
            else
            {
                close(client_fd);
                FD_CLR(client_fd, &rfds);
                printf("del socket %d from select pipe. \n", client_fd);
                client_fd = -1;
                break;
            }
            FD_SET(0, &rfds);
            if (FD_ISSET(0, &rfds))
            {
                bzero(buf, MAX_BUF_SIZE + 1);
                fgets(buf, MAX_BUF_SIZE, stdin);
                if (!strncasecmp(buf, "quit", 4))
                {
                    printf("quit chat!\n");
                    break;
                }
                sin_size = send(client_fd, buf, strlen(buf)-1, 0);
                if (sin_size > 0)
                {
                    printf("message: %s\t send successfully, total %d bytes!\n", buf, sin_size);
                }
                else
                {
                    printf("message: %s\t send failure, error code is %d, error message is %s\n",
                            buf, errno, strerror(errno));
                }
            }
        }
        for (i=0; i<MAX_LISTEN; i++)
        {
            if (maxfd < client_fd)
            {
                maxfd = client_fd;
            }
        }
        printf("This cycle of select loop over, max_fd = %d\n", maxfd);
    }
    printf("any chat?(no -> quit)");
    fflush(stdout);
    bzero(buf, MAX_BUF_SIZE + 1);
    fgets(buf, MAX_BUF_SIZE, stdin);
    if (!strncasecmp(buf, "no", 2))
    {
        printf("quit chat3!\n");
    }

    close(sockfd);
    return 0;
}

[ 本帖最后由 shenxiaocheng 于 2009-7-8 16:08 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2009-07-08 16:49 |只看该作者

论坛徽章:
0
3 [报告]
发表于 2009-07-08 18:32 |只看该作者
又帖上来了,在conn_fd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size);之后单独建立个线程来对这个
conn_fd进行交互处理,要不然就在sin_size = recv(client_fd, buf, MAX_BUF_SIZE, 0);挂死了。

论坛徽章:
0
4 [报告]
发表于 2009-07-08 20:03 |只看该作者
编译都通不过就贴上来了,
还有给数组名client_fd 赋 -1的

论坛徽章:
0
5 [报告]
发表于 2009-07-09 16:36 |只看该作者

回复 #4 bsdc 的帖子

手误,不好意思
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP