现在的位置: 首页 > 综合 > 正文

Linux C client/server简单聊天室 select精彩例子!

2013年10月24日 ⁄ 综合 ⁄ 共 7355字 ⁄ 字号 评论关闭

/*----------------------------server-------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <fcntl.h>
#include<netdb.h>

#define PORT 8888
#define MAXLINE 1024
#define MAXSTEN 20

int n=0,client[MAXSTEN];
fd_set allset;

/*---------------------------------------------------------------------------------------*/
/*                                                                                       */
/*                                       链表各个功能函数                                  */
/*                                                                                       */
/*---------------------------------------------------------------------------------------*/
struct client_msg
{
    char name[20];
    char *clientip;
    int fdnumber;
    int portnumber;
    struct client_msg *next;
};

struct client_msg *list_create()
{
    struct client_msg *lhead;
    lhead=(struct client_msg *)malloc(sizeof(struct client_msg));
    lhead->next=NULL;

    return lhead;
}

void list_save(struct client_msg *head,char name[20],int ifdnumber,int iportnumber)
{
    struct client_msg *ihead,*inew;
    ihead=head;
    inew=(struct client_msg *)malloc(sizeof(struct client_msg));
    strcpy(inew->name,name);
    inew->fdnumber=ifdnumber;
    inew->portnumber=iportnumber;
    inew->next=NULL;
    if(NULL==head)
    {
        ihead=inew;
    }else{
        while(ihead->next!=NULL)ihead=ihead->next;
        ihead->next=inew;
    }
}

void list_delect(struct client_msg *head,int dfd)
{
    struct client_msg *dhead;
    dhead=head;

    if(NULL==head)
    {
        printf("链表为空!\n");
        return;
    }else if(NULL==head->next){
        if(head->fdnumber!=dfd)
        {
            printf("没有找到相关套接字!\n");
            return;
        }else{
            dhead=dhead->next;
        }
    }else{
        while(dhead->next->fdnumber!=dfd)dhead=dhead->next;
        dhead->next=dhead->next->next;
    }
}

char *list_find(struct client_msg *head,int ffd)
{
    struct client_msg *fhead;
    fhead=head;

    if(NULL==head)
    {
        printf("链表为空!\n");
    }else{
        while(fhead->fdnumber!=ffd)fhead=fhead->next;
        return fhead->name;
    }
}

void list_print(struct client_msg *head)
{
    struct client_msg *phead;
    phead=head;

    if(NULL==head)
    {
        printf("链表为空!\n");
    }else{
        printf("\n\n目前服务器在线人数:%d",\n);
        printf("n-----------------------------------------------------------------n");
        printf("\t\t昵称:\t\t端口:\t\t套接字:\n");
        while(phead!=NULL)
        {
            printf("\t\t%s\t\t%d\t\t%d\n",
                   phead->name,phead->portnumber,phead->fdnumber);
            phead=phead->next;
        }
        printf("\n-----------------------------------------------------------------\n");
    }
}

/*---------------------------------------------------------------------------------------*/
/*                                                                                       */
/*                                       服务器各个功能函数                                 */
/*                                                                                       */
/*---------------------------------------------------------------------------------------*/
int server_create()
{
    int listenfd;
    struct sockaddr_in servaddr;

    if((listenfd=socket(AF_INET,SOCK_STREAM,0))==-1)
    {
        printf("socket error:%s\n",strerror(errno));
        exit(1);
    }

    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family=AF_INET;
    servaddr.sin_port=htons(PORT);
    servaddr.sin_addr.s_addr=INADDR_ANY;

    if(bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr))==-1)
    {
        printf("bind error:%s\n",strerror(errno));
        exit(1);
    }

    if(listen(listenfd,MAXSTEN)==-1)
    {
        printf("listen error:%s\n",strerror(errno));
        exit(1);
    }
    printf("等待客户端连接... ...\n");
    return listenfd;
}

int server_accept(int listenfd,struct client_msg *head)
{
    int connfd;
    struct sockaddr_in cliaddr;
    socklen_t clilen;
    char tempname[20];

    printf("发现新的客户端正在连接服务器... ...\n");
    clilen=sizeof(cliaddr);
    if((connfd=accept(listenfd,(struct sockaddr *)&cliaddr,&clilen))==-1)
    {
        printf("accept error :%s\n",strerror(errno));
        exit(1);
    }
    recv(connfd,tempname,sizeof(tempname),0);
    printf("客户端连接服务器成功!正在获取客户端的资料... ...\n");
    printf("昵称:%s,端口:%d,IP地址:%s\n",
           tempname,ntohs(cliaddr.sin_port),inet_ntoa(cliaddr.sin_addr));

    list_save(head,tempname,connfd,ntohs(cliaddr.sin_port));
    n++;
    list_print(head);
    return connfd;


}

void server_recv(struct client_msg *head,int sockfd,int i)
{
    char name[20],buff[MAXLINE+1];
    int len,k;
    memset(buff,0,sizeof(buff));
    len=recv(sockfd,buff,sizeof(buff),0);

    if(len==0)
    {
        strcpy(name,list_find(head,sockfd));
        printf("\n用户%s 主动退出了聊天室!\n",name);
        close(sockfd);
        FD_CLR(sockfd,&allset);
        list_delect(head,sockfd);
        client[i]=-1;
        n--;
        list_print(head);
    }else if(len<0){
        strcpy(name,list_find(head,sockfd));
        printf("\n由于网络异常!用户%s 掉线!\n",name);
        printf("error:%s\n",strerror(errno));
        close(sockfd);
        FD_CLR(sockfd,&allset);
        list_delect(head,sockfd);
        client[i]=-1;
        n--;
        list_print(head);
    }else{
        printf("%s",buff);
        for(k=0;k<MAXSTEN;k++)
        {
            if(client[k]>0)
            {
                send(client[k],buff,sizeof(buff),0);
            }
        }
        memset(buff,0,sizeof(buff));
    }
}

void server_command(struct client_msg *head)
{
    int chance,fd,j;
    char commandbuff[20];
    fgets(commandbuff,sizeof(commandbuff),stdin);

    if(strcmp(commandbuff,"command\n")==0)
    {
        printf("\n\n\n1.查看服务器成员\n2.断开成员的连接\n3.退出服务器\n");
        printf("请输入:");
        scanf("%d",&chance);

        switch (chance) {
        case 1:
            list_print(head);
            break;
        case 2:
            printf("请输入客户端的套接字:");
            scanf("%d",&fd);
            memset(commandbuff,0,sizeof(commandbuff));
            strcpy(commandbuff,list_find(head,fd));
            list_delect(head,fd);
            close(fd);
            FD_CLR(fd,&allset);
            for(j=0;j<MAXSTEN;j++)
            {
                if(client[j]==fd)
                {
                    client[j]=-1;
                    break;
                }
            }
            n--;
            printf("\n用户%s 已经被强制下线!\n",commandbuff);
            list_print(head);
            break;
        case 3:
            printf("服务器已经关闭!\n");
            exit(0);
            break;
        default:
            printf("不是有效命令!!\n");
            break;
        }
    }

}

int main()
{
    int listenfd,sockfd;
    int i,maxfd;
    struct client_msg *head;

    listenfd=server_create();

    maxfd=listenfd;
    for(i=0;i<MAXSTEN;i++)
    {
        client[i]=-1;
    }

    head=list_create();
    while(1)
    {
        FD_ZERO(&allset);
        FD_SET(0,&allset);
        FD_SET(listenfd,&allset);

        for(i=0;i<MAXSTEN;i++)
        {
            if(client[i]>0)
                FD_SET(client[i],&allset);
        }

        select(maxfd+1,&allset,NULL,NULL,NULL);

        if(FD_ISSET(listenfd,&allset))
        {
            for(i=0;i<MAXSTEN;i++)
            {
                if(client[i]<0)
                {
                    client[i]=server_accept(listenfd,head);
                    FD_SET(client[i],&allset);
                    break;
                }
            }
            if(i==MAXSTEN)
            {
                printf("已经达到服务器人数上限!无法建立新的连接\n");
            }
            if(client[i]>maxfd)
                maxfd=client[i];
        }
        if(FD_ISSET(0,&allset))
        {
            server_command(head);
        }
        for(i=0;i<MAXSTEN;i++)
        {
            if((sockfd=client[i])<0)
            {
                continue;
            }else{
                if(FD_ISSET(sockfd,&allset))
                {
                    server_recv(head,sockfd,i);
                    break;
                }
            }
        }
    }
     return 0;
}

/*-----------------------------------client---------------------------------------*/

#include<lilin.h>    //跟server 的头文件一样
#include<time.h>

#define PORT 8888
#define MAXLINE 1024

int main(int argc, char *argv[])
{
   

    int sockfd,maxfd,len;
    char msg1[MAXLINE+1];
    char msg2[MAXLINE+1];
    char msg3[MAXLINE+1];
    char name[40],*str;
    char strquit[]={"quitn"};
    int quit=1;

    static char timestr[40];

    struct sockaddr_in servaddr;

    time_t t;
    struct tm *nowtime;
    fd_set allset;

    if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
    {
        printf("socket error :%d %sn",errno,strerror(errno));
        exit(1);
    }



    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family=AF_INET;
    servaddr.sin_port=htons(PORT);
    servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");

    printf("正在连接服务器... ...\n");
    if(connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr))==-1)
    {
        printf("connect error :%s\n",strerror(errno));
        exit(1);
    }
    printf("连接服务器成功!\n");
    printf("请输入你的昵称:");
    scanf("%s",name);
    send(sockfd,name,sizeof(name),0);
    printf("%s 欢迎来到聊天室!(quit->退出)\n",name);
    fflush(stdin);
    maxfd=sockfd;

    while(1)
    {
        FD_ZERO(&allset);
        FD_SET(sockfd,&allset);
        FD_SET(0,&allset);
        memset(msg1,0,sizeof(msg1));
        memset(msg2,0,sizeof(msg1));
        memset(msg3,0,sizeof(msg1));

        select(maxfd+1,&allset,NULL,NULL,NULL);
        if(FD_ISSET(0,&allset))
        {
            fgets(msg1,sizeof(msg1),stdin);
            if(strcmp(msg1,strquit)==0)
            {
                close(sockfd);
                printf("已经断开与服务器的连接,退出聊天室!\n");
                quit=0;
            }
            else
            {
                time(&t);
                nowtime=localtime(&t);
                strftime(timestr,sizeof(timestr),"%Y-%m-%d %H:%M:%S",nowtime);
                snprintf(msg2,sizeof(msg2),"%s %s:%s",timestr,name,msg1);

                send(sockfd,msg2,sizeof(msg2),0);
            }
        }
        if(FD_ISSET(sockfd,&allset))
        {
            if(quit)
            {
                len=recv(sockfd,msg3,sizeof(msg3),0);
                if(len<=0)
                {
                    printf("服务器出现故障,已经断开与服务器的连接!\n");
                    quit=0;
                    close(sockfd);
                }
                else
                {
                    printf("%s",msg3);
                }
            }
            else
            {
                printf("已经断开与服务器的连接,无法发送消息!\n");
            }
        }
    }

    return 0;
}
 

这些功能都比较简单,实现不难,都是书上的简单应用。实际上如果仅仅是实现上述功能,不必如此复杂,但是自己觉得初学时就应该把各个功能代码分开。

因为工作时,不会让你写万整个程序,而是把功能分给不同的人写。

笔者愚笨,刚开始接触UNIX网络编程,如有错误,或者BUG,可留言联系。

抱歉!评论已关闭.