主题 : select实现tcp服务器    服务器收一个字符    客户端才能收两个字符   这样循环 复制链接 | 浏览器收藏 | 打印
级别: 新手上路
UID: 63206
精华: 0
发帖: 13
金钱: 65 两
威望: 13 点
综合积分: 26 分
注册时间: 2012-02-16
最后登录: 2012-03-09
楼主  发表于: 2012-02-27 15:34

 select实现tcp服务器    服务器收一个字符    客户端才能收两个字符   这样循环

//:server.c --use select() impletate multiplexion, base on TCP
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <sys/select.h>
#include <time.h>
#include <arpa/inet.h>

#include <lib.h>

#define SERV_PORT 6000
#define BACK_LOG 5
#define MAX_LINE BUFSIZ
#define SERVADDR "192.168.1.229"
typedef struct cli_node
{
    int clifd;
    struct cli_node *next;
} cli_node, *cli_list;

/*add a client's fd*/
cli_list add_cli(cli_list head, int fd)//建立链表
{
    cli_list p = head;

    cli_list new_cli = (cli_list) malloc(sizeof(cli_node));

    while (p->next)
        p = p->next;
    new_cli->clifd = fd;
    new_cli->next = NULL;
    p->next = new_cli;
    return (head);
}

/*delete a client's fd*/
cli_list delete_cli(cli_list head, int fd)//删除链表
{
    cli_list p = head, q = head->next;

    while (q->clifd != fd) {
        p = q;
        q = q->next;
    }
    p->next = q->next;
    close(fd);
    free(q);
    return (head);
}

/*main*/
int main(int argc, char **argv)
{
    /*definition */
    int i, ofd, listenfd, connfd = 0,f;
    cli_list head, ph, qh;
    int b_reuse = 1;
    socklen_t len;
    struct timeval timeout={3,0};
    struct sockaddr_in servaddr, cliaddr;
    char buf[MAX_LINE], addr[15];
    fd_set readset;

    head = (cli_list) malloc(sizeof(cli_node));
    head->next = NULL;
    for (i = 3; i < sysconf(_SC_OPEN_MAX); i++)//?
        close(i);
    listenfd = socket(AF_INET, SOCK_STREAM, 0);    // listen socket
    if(listenfd < 0) {
        fprintf(stderr,"socket() error!, listenfd = %d\n", listenfd);
        exit(1);        
    }    
    head->clifd = listenfd;
    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof(int));//设置套接口选项层
    bzero(&servaddr, sizeof(servaddr));
    /*set servaddr */
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERV_PORT);
#if 1
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
#else
    servaddr.sin_addr.s_addr=inet_addr(SERVADDR);
#endif    
    /*bind the listener to the local port */
    if (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) != 0) {
        perror("bind");
        exit(1);
    }
    /*ok, now listen */
    listen(listenfd, BACK_LOG);
    while (1) {
        /*initialize */
        FD_ZERO(&readset);//将readset集合清零
        FD_SET(listenfd, &readset);//将服务器创建的套接字加入readset集合
        /*add file describtions to fdset */
        ph = head;
        while (ph->next) {
            FD_SET(ph->next->clifd, &readset);//将链表加入readset集合
            ph = ph->next;
        }
        /*creat a select-list */
        select((ph->clifd) + 1, &readset, NULL, NULL,&timeout);
        

        /*add a new connection to the select-list */
        if (FD_ISSET(listenfd, &readset)) {//测试listenfd是否在集合内
            len = sizeof(cliaddr);
            connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &len);
            head = add_cli(head, connfd);
            continue;
        }
        
        //FD_SET(connfd,&readset);
        //FD_SET(ofd,&readset);
        /*proccess an eixsted connetction */
        for (connfd = (listenfd + 1); connfd <= (ph->clifd); connfd++) {
            if (FD_ISSET(connfd, &readset)) {
                fprintf(stderr,"server: get a socket data:");
                    
                    
                if (recv(connfd, buf, MAX_LINE, 0) <= 0) {    // something is wrong! delete it!
                    head = delete_cli(head, connfd);
                    break;  
                } else {
                     fprintf(stderr,"%s\n", buf);
                }
                
                    for (ofd = listenfd + 1; ofd <= ph->clifd; ofd++) {
                        if (ofd != connfd);    // connfd is the current active socket
                        if (FD_ISSET(ofd,&readset)){    
                            scanf ("%s",buf);
                            if (send(ofd, buf, MAX_LINE, 0)<0)    // ofd is "other fd"
                            {
                                head=delete_cli(head,ofd);
                                break;
                            }
                        }
                    }
                }
            }
        }
    }                            
级别: 新手上路
UID: 63206
精华: 0
发帖: 13
金钱: 65 两
威望: 13 点
综合积分: 26 分
注册时间: 2012-02-16
最后登录: 2012-03-09
1楼  发表于: 2012-02-27 19:41

 回 楼主(s3c11) 的帖子

求解    
级别: 新手上路
UID: 63294
精华: 0
发帖: 7
金钱: 35 两
威望: 7 点
综合积分: 14 分
注册时间: 2012-02-17
最后登录: 2012-07-05
2楼  发表于: 2012-02-28 09:04

 Re:select实现tcp服务器  服务器收一个字符  客户端才能收两个字符  这样循环

有UDP的没
级别: 新手上路
UID: 63206
精华: 0
发帖: 13
金钱: 65 两
威望: 13 点
综合积分: 26 分
注册时间: 2012-02-16
最后登录: 2012-03-09
3楼  发表于: 2012-02-28 10:26

 回 2楼(studyfr) 的帖子

没有   有没有找出这是什么问题啊
级别: 侠客
UID: 59279
精华: 0
发帖: 84
金钱: 430 两
威望: 86 点
综合积分: 168 分
注册时间: 2011-11-22
最后登录: 2012-12-04
4楼  发表于: 2012-03-29 13:45

 Re:select实现tcp服务器  服务器收一个字符  客户端才能收两个字符  这样循环

学习