1.当客户端(client)打开,输入昵称后服务器(server)端以及客户端的现象
2.当客户端发送消息,以及服务端发送消息,以及客户端退出时现象
1.因为服务端和客户端都需要具备接收数据和发送数据的能力,因此需要使用多个线程分别完成接收和发送的操作(相关函数pthread_create())
2.因为需要通过服务端给每个用户群发消息,所以用户的信息需要储存,用数组和链表都可以,这里本人用的是链表
3.因为UDP协议发送信息时用的是sedto()函数,每次发送数据都需要提供发送目标的ip和端口号,因此我们需要定义一个结构体来存放每个登录用户的端口号和ip号等信息.
#ifndef _HEAD_H_
#define _HEAD_H_
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <stdlib.h>
#include <linux/in.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>//发送信息的标志变量
#define LOGIN 0
#define QUIT 1
#define SESSION 2
#define SERVER 3
#define RENAME 4//存放客户端发送信息
typedef struct msg{int flag;char name[16];char info[64];
}msg;//用来保存单个用户的ip,端口号等信息
typedef struct usermsg{char user_ip[32];unsigned short user_port;char user_name[16];
}usermsg;//存放所有用户信息的链
typedef struct userlink{usermsg user;struct userlink *next;
}userlink;int link_creat(userlink **); //创建链表
int link_add(userlink *,usermsg *,int); //添加用户
int myperror(int,char*); //报错信息(写到后面忘了这个函数了,后面写的函数几乎都没有做判断...)
int link_delete(userlink*,usermsg*,int);//用户退出,删除退出用户的信息
int mass(userlink*,usermsg*,msg*,int); //服务器给各个客户端群发信息的函数
void* client_thread(void*); //客户端thread_create()创建线程函数的最后一个参数,该线程用于接收来自服务器的消息
userlink* link_select(userlink*,usermsg*);//查找指定用户的函数
void* clientmsg_thread(void *); //服务端thread_create()创建线程函数的最后一个参数,该线程用于给客户端发送服务端的消息
void* servermsg_thread(void *); //服务端thread_create()创建线程函数的最后一个参数,该线程用于给客户端发送其他客户端的消息
#endif
#include"head.h"
//自定义的报错函数
int myperror(int flag,char *name){if(flag < 0){printf(">>server : %s is error",name);perror(":");exit(-1);return 0;}else{printf(">>server : %s is succeedn",name);return 0;}
}
//创建链表
int link_creat(userlink **p){if((*p) == NULL){(*p) = (userlink*)malloc(sizeof(userlink));(*p) -> next = NULL;(*p) -> user.user_port = 0;return 0;}puts("==SERVER== :link is exit");return 0;
}
//添加用户,并给所有人发送登录信息
int link_add(userlink *p,usermsg *umsg,int sockfd){if(p){userlink *new = (userlink*)malloc(sizeof(userlink));new -> next = p -> next;p -> next = new;p -> user.user_port ++;strcpy(new -> user.user_ip,umsg -> user_ip);new -> user.user_port = umsg -> user_port;strcpy(new -> user.user_name,umsg->user_name);//在服务端打印登入用户的名字,ip,以及端口号printf(">>server : %s is login,--[ip : %s][port : %u]--n",umsg -> user_name,umsg -> user_ip,umsg -> user_port);new = NULL;//定义一个新的数据包msg smsg;//给数据包定义一个flag标志位,然后往其中填充一条"xxx"用户登录的消息smsg.flag = SERVER;memset(smsg.info,'