23062网络编程day7

网络聊天室编写(基于UDP)

服务器

#include 

#define PORT 8888               //端口号:接收方绑定的端口号
#define IP "192.168.114.56"    //本机IP

#define ERR_MSG(msg)  do{\
    fprintf(stderr, "__%d__:", __LINE__); \
    perror(msg);\
}while(0)

//需要传入到分支线程的参数
typedef struct Climsg{
    char code;
    char user[32];
	char text[128];
}msg_t;

//创建链表存储数据
typedef struct Node{
    struct sockaddr_in addr; 
    struct Node *next;
}node_t,*nodeptr; 

//创建节点的函数
int create_node(nodeptr *phead){
    *phead = (nodeptr)malloc(sizeof(node_t));
    if(NULL == *phead){
        printf("内存分配失败\n");
        exit(-1);
    }
    (*phead)->next=NULL;
    return 0;
}
//尾插法
int insert_data_by_tail(node_t *phead,struct sockaddr_in addr){
     if(NULL == phead)
	 {
        printf("参数为NULL,请检查\n");
        return -1;
     }
    //将新客户端使用尾插法插入链表中
    nodeptr pnew = NULL;
    create_node(&pnew);
    pnew->addr = addr;  
    nodeptr ptemp =phead;
    while(ptemp->next != NULL)
	{
        ptemp = ptemp->next;
    }
    //让尾结点的指针域指向新节点
    ptemp->next = pnew;
    return 0;
}

int main(int argc, const char *argv[])
{
	int sfd = 0;
    if(-1==(sfd=socket(AF_INET,SOCK_DGRAM,0))){
        ERR_MSG("socket error");
    }
    struct sockaddr_in sin;
    memset(&sin,0,sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(PORT);
    sin.sin_addr.s_addr = inet_addr(IP);
    socklen_t sin_len = sizeof(sin);
 
    if(-1 == bind(sfd,(struct sockaddr *)&sin,sin_len)){
        ERR_MSG("bind error");
    } 
 
    struct sockaddr_in cin,temp_cin;
    memset(&cin,0,sizeof(cin));
    socklen_t cin_len = sizeof(cin);
 
    char name[32] = {0};
    pid_t pid = 0;
    msg_t msg;
    msg_t msg_send;
    //创建头结点
    nodeptr phead;
    create_node(&phead);
    phead->addr = cin;
 
    if(-1 == (pid = fork())){
        ERR_MSG("fork error");
    }else if(0 == pid){   //子进程 接收数据 (1、d 登录操作 2、q 群聊操作 3、t 退出操作)  
        while(1){
            memset(&msg,0,sizeof(msg));
            if(-1 == recvfrom(sfd, (void*)&msg, sizeof(msg),0, (struct sockaddr *)&cin,&cin_len)){
                perror("recv error");
            }    
        switch(msg.code){
            case 'd':
                printf("用户[%s]上线\n", msg.user);              
                insert_data_by_tail(phead,cin);
                nodeptr q=phead->next;                
                while(q != NULL){
                    msg.code='d';
                    if(-1 == sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr *)&q->addr,sizeof(q->addr)))
					{
                        ERR_MSG("send error");
                    }
                    q=q->next;
                }
                break; 
            case 'q':                     
                if(strcmp("系统提示",msg.user)!=0){
                printf("[%s]:%s\n",msg.user, msg.text);
                }
                node_t *p = phead->next;                
                while(p != NULL){
                    msg.code='q';
                    if(-1 == sendto(sfd,(void *)&msg,sizeof(msg),0,(struct sockaddr *)&p->addr,sizeof(p->addr))){
                        ERR_MSG("send error");
                    }
                    p=p->next;
                }                
                break; 
            case 't':    
                printf("用户[%s]:已退出\n", msg.user);
                nodeptr t = phead; 
                nodeptr pdel = NULL;               
                while(t->next != NULL){
                    msg.code='t';
                    if( 0 == memcmp(&(t->next->addr), &cin,sizeof(cin))){
                        pdel = t->next;
                         t->next = pdel->next;
                        free(pdel);
                    }else{
                        t = t->next;
                        if(-1 == sendto(sfd, &msg,sizeof(msg),0,(struct sockaddr *)&t->addr,sizeof(t->addr))){
                            ERR_MSG("send error");
                        }
                    }    
                }     
                break;
            }
        }
    }else if(0 < pid){
        //父进程 发送系统消息
        while(1){  
            strcpy(msg_send.user,"系统");
            memset(msg_send.text,0,128);
            fgets(msg_send.text,128,stdin);
            msg_send.text[strlen(msg_send.text)-1] = '\0';
            msg_send.code = 'q';              
            if(-1 == sendto(sfd,&msg_send,sizeof(msg_send),0,(struct sockaddr *)&sin,sin_len)){
                ERR_MSG("send error");                
            }               
        }
    } 
    kill(pid, SIGKILL);
    wait(NULL);//给子进程回收资源
    exit(0);     
    close(sfd);
    return 0;
}

客户端

#include 

#define PORT 8888               //端口号:接收方绑定的端口号

#define ERR_MSG(msg)  do{\
    fprintf(stderr, "__%d__:", __LINE__); \
    perror(msg);\
}while(0)
#define IP  "192.168.114.56"    //本机IP,ifconfig
#define M 32
#define N 128
typedef struct _Node{
    struct sockaddr_in addr;
    struct _Node *next;
}node_t;

typedef struct _Msg{
    char code;
    char user[M];
    char text[N];
}msg_t;

int main(int argc, const char *argv[])
{
  
    //创建用户数据报套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == sockfd){
        ERR_MSG("socket error");
    }
 
    //填充服务器网络信息结构体
    struct sockaddr_in sin;
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;

    sin.sin_port = htons(PORT);
    sin.sin_addr.s_addr = inet_addr(IP);
    socklen_t sin_len = sizeof(sin);
 
    int res = 0;
    char name[32]={0};
    msg_t msg;
    pid_t pid;
 
    struct sockaddr_in cin;
    memset(&cin,0,sizeof(cin));
    socklen_t cin_len = sizeof(cin);
 
    //输入用户名,完成登陆操作
    printf("请输入登录信息:");
    msg.code = 'd';
    memset(msg.user, 0, 32);
    fgets(name, 32, stdin);//在终端获取用户名
    strcpy(msg.user,name);
    msg.user[strlen(msg.user) - 1] = '\0';
	if (-1 == sendto(sockfd,&msg,sizeof(msg),0, (struct sockaddr *)&sin,sin_len)){  //给服务器发送用户名
        ERR_MSG("send error");
    }
 
    //创建进程
    if(-1 == (pid = fork())){
        ERR_MSG("fork error");
    }else if(0 == pid){   
        //子进程 接收数据  
        while (1){
            memset(&msg,0,sizeof(msg));
            //接收服务器的应答
            if (-1 == (res=recvfrom(sockfd, &msg, sizeof(msg), 0,(struct sockaddr *)&sin,&sin_len))){
                ERR_MSG("recv error");
            }                         
            if(strcmp(msg.user,name) == -10){               
                continue;
            }else{
                //打印应答信息
                switch(msg.code){
                    case 'd':
                        printf("用户[%s]登录上线了....\n", msg.user); 
                        break; 
                    case 'q':
                        printf("[%s]:%s\n",msg.user,msg.text);
                        break;
                    case 't':            
                        printf("用户[%s]已退出\n", msg.user); 
                    break;
                }  
            } 
        }    
        }else if(0 < pid){
            //父进程 发送数据(2、q:群聊操作  3、t:退出操作)
            while(1){
                //在终端获取群聊
                memset(msg.text, 0, 128);
                fgets(msg.text, 128, stdin);
                msg.text[strlen(msg.text) - 1] = '\0'; //清空结尾的 '\n'               
                if( 0 ==strcmp(msg.text, "quit")){
                    msg.code = 't'; 
                    if (-1 == sendto(sockfd, &msg, sizeof(msg), 0,(struct sockaddr *)&sin,sin_len)){
                        ERR_MSG("send error");     
                    }   
                    break;
                }else{
                    msg.code = 'q';    
                }
                //给服务器发送群聊消息
                if (-1 == sendto(sockfd, &msg, sizeof(msg), 0,(struct sockaddr *)&sin,sin_len)){
                        ERR_MSG("send error");
                }
            }     
        }      
    //关闭套接字
    close(sockfd);
    return 0;
}

你可能感兴趣的:(网络)