用select实现的简单聊天室

来源:互联网 发布:php正则表达式匹配邮箱 编辑:程序博客网 时间:2024/06/03 02:15
  1. 服务端
    #include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <stdlib.h>#include <assert.h>#include <stdio.h>#include <string.h>#include <errno.h>#include <fcntl.h>#include <vector>#include <string>using namespace std;int main(int argc,char* argv[]){    printf("server start up\n");    if(argc <= 3)    {        printf("usage:%s ip port backlog\n",basename(argv[0]));        return 1;    }    //IP地址    const char* ip = argv[1];    //端口号    int port = atoi(argv[2]);    //内核监听队列的最大长度(完全连接的socket)    int backlog = atoi(argv[3]);    //创建socket(TIP/IP协议族,流式socket)    int server_sockfd = socket(PF_INET,SOCK_STREAM,0);    //最大连接数,初始化为server_sockfd    int max_fd = server_sockfd;    //    vector<int> connFds;    connFds.reserve(backlog);    //TCP/IP协议族的socket地址结构体    struct sockaddr_in server_addr;    bzero(&server_addr,sizeof(server_addr));    server_addr.sin_family = AF_INET;//TCP/IPv4的地址族    inet_pton(AF_INET,ip,&server_addr.sin_addr);//将IP地址字符串转换为二进制的整数并赋给addr.sin_server_addr    server_addr.sin_port = htons(port);//端口,host to net,将主机字节序(小端)转换为网络字节序(大端)    //将文件描述符sock和socket地址关联,仅服务端需要,客户端自动绑定地址    //注意需要强制转换为 struct sockaddr*    int ret = bind(server_sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr));    assert(ret != -1);    //监听    ret = listen(server_sockfd,backlog);    assert(ret != -1);    //客户端地址信息    struct sockaddr_in client_addr;    socklen_t client_addrlength = sizeof(client_addr);    char buf[1024]={0};    //文件描述符集合    fd_set read_fds;    fd_set  exception_fds;    FD_ZERO(&read_fds);    FD_ZERO(&exception_fds);    //超时//    struct timeval timeout;//    timeout.tv_sec = 500;             //秒//    timeout.tv_usec = 0 ;            //微秒    while(1)    {        FD_SET(server_sockfd,&read_fds);        for(int i =0;i<connFds.size();++i)        {            FD_SET(connFds[i],&read_fds);            FD_SET(connFds[i],&exception_fds);        }        int ret = select(max_fd+1,&read_fds,NULL,&exception_fds,NULL);        if( ret  ==  -1)        {            //printf("selection failure\n");            perror("select");            break;        }        else if( ret == 0)        {            perror("timeout");            break;        }        for(vector<int>::iterator it = connFds.begin();it != connFds.end();)        {            if( FD_ISSET(*it,&read_fds) )            {                memset(buf,0,sizeof(buf));                int ret = recv(*it,buf,sizeof(buf)-1,0);                if(ret <= 0)                {                    perror("recv");                    close(*it);                    FD_CLR(*it,&read_fds);                    printf("A client disconnectd\n");                    it = connFds.erase(it);                    continue;                }                else                {                    buf[ret] = '\0';                    printf("recived:%s\n",buf);                    for(int i =0;i<connFds.size();++i)                    {                        if(connFds[i] != *it)                        {                            string str("some one said:");                            str.append(buf);                            int ret = send(connFds[i],str.c_str(),str.length(),0);                            if(ret<=0)                            {                                perror("send");                            }                        }                    }                }            }            ++it;        }        for(vector<int>::iterator it = connFds.begin();it != connFds.end();++it)        {            if(FD_ISSET(*it,&exception_fds))            {                memset(buf,0,sizeof(buf));                int ret = recv(*it,buf,sizeof(buf)-1,MSG_OOB);                if(ret < 0)                {                    perror("exception");                }                else                {                    buf[ret] = '\0';                    printf("%s",buf);                }            }        }        if( FD_ISSET(server_sockfd,&read_fds) )        {            //接受连接,并将被接受的远端sock地址信息保存在第二个参数中            int newfd = accept(server_sockfd,(struct sockaddr*)&client_addr,&client_addrlength);            if(newfd < 0)            {                perror("accept");                close(newfd);                return -1;            }            else            {                connFds.push_back(newfd);                max_fd = newfd;                //inet_ntoa(struct addr_in) 将IP地址转换为字符串并返回                //只是从监听队列中取出连接,即使客户端已经断开网络连接也会accept成功                printf("accept client_addr %s\n",inet_ntoa(client_addr.sin_addr));            }        }    }    //关闭连接,实际只是socket的引用-1,必须引用为0才会真正关闭    for(int i= 0;i< connFds.size();++i)    {        close(connFds[i]);    }    close(server_sockfd);    return 0;}
  2. 客户端
    #include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <signal.h>#include <unistd.h>#include <stdlib.h>#include <assert.h>#include <stdio.h>#include <string.h>#include <errno.h>#include <string>#include <iostream>using namespace std;int main(int argc,char* argv[]){    if(argc <= 2)    {        printf("usage:%s ip port\n",basename(argv[0]));        return 1;    }    const char* ip = argv[1];    int port = atoi(argv[2]);    struct sockaddr_in remote_addr;    bzero(&remote_addr,sizeof(remote_addr));    remote_addr.sin_family = AF_INET;    inet_pton(AF_INET,ip,&remote_addr.sin_addr);    remote_addr.sin_port = htons(port);    int remote_sockfd = socket(PF_INET,SOCK_STREAM,0);    assert(remote_sockfd>=0);    //连接    if(connect(remote_sockfd,(struct sockaddr*)&remote_addr,sizeof(struct sockaddr)) < 0)    {        perror("connect:");        return -1;    }    else    {        printf("connect success\n");    }    //文件描述符集合    fd_set read_fds;    FD_ZERO(&read_fds);    FD_SET(remote_sockfd,&read_fds);    //add stand input device    FD_SET(0,&read_fds);    int ret= -1;    string str;    char  buf[1024]={0};    while (1)    {        FD_SET(remote_sockfd,&read_fds);        FD_SET(0,&read_fds);//add stand input device        ret = select(remote_sockfd+1,&read_fds,NULL,NULL,NULL);        if(ret < 0)        {            perror("select");        }        if(FD_ISSET(remote_sockfd,&read_fds))        {            ret = recv(remote_sockfd,buf,sizeof(buf),0);            if(ret > 0)            {                str.clear();                buf[ret] = '\0';                str.append(buf);                cout<<str<<endl;            }        }        if(FD_ISSET(0,&read_fds))        {            memset(buf,0,sizeof(buf));            scanf("%s",buf);            ret = send(remote_sockfd,buf,strlen(buf),0);            if(ret<=0)            {                perror("send");            }            else            {                str.clear();                str = str+"send: "+buf+"success\n";                cout<<str;            }        }    }    close(remote_sockfd);}

 

0 0