抖音做我女朋友网站,ai室内设计生成软件,网站建设教程详解,网页设计案例教程课后实训答案要求#xff1a;1.有新用户登录#xff0c;其他在线的用户可以收到登录信息 2.有用户群聊#xff0c;其他在线的用户可以收到群聊信息 3.有用户退出#xff0c;其他在线的用户可以收到退出信息 4.服务器可以发送系统信息
效果图#xff1a; service.c
#include head…要求1.有新用户登录其他在线的用户可以收到登录信息 2.有用户群聊其他在线的用户可以收到群聊信息 3.有用户退出其他在线的用户可以收到退出信息 4.服务器可以发送系统信息
效果图 service.c
#include head.h
typedef struct _MSG
{char type; // 类型 L 登录 C 群聊 Q 退出char name[32];char txt[128];
} msg_t;
typedef struct _NODE
{struct sockaddr_in clientaddr;struct _NODE *next;
} node_t;
void create_node(node_t **p);
void do_login(node_t *phead, msg_t msg, int sockfd, struct sockaddr_in clientaddr);
void do_chat(node_t *phead, msg_t msg, int sockfd, struct sockaddr_in clientaddr);
void do_quit(node_t *phead, msg_t msg, int sockfd, struct sockaddr_in clientaddr);int main(int argc, const char *argv[])
{// 入参合理性检查if (argc ! 3){printf(usage error:%s ip port...\n, argv[0]);exit(-1);}int sockfd 0;// 创建套接字if (-1 (sockfd socket(AF_INET, SOCK_DGRAM, 0))){perror(socket error);exit(-1);}// 填充服务器网络信息结构体struct sockaddr_in serveraddr;socklen_t serveraddr_len sizeof(serveraddr);memset(serveraddr, 0, sizeof(serveraddr));serveraddr.sin_family AF_INET;serveraddr.sin_addr.s_addr inet_addr(argv[1]);serveraddr.sin_port htons(atoi(argv[2]));struct sockaddr_in clientaddr;socklen_t clientaddr_len sizeof(clientaddr);// 绑定if (-1 (bind(sockfd, (struct sockaddr *)serveraddr, serveraddr_len))){perror(bind error);exit(-1);}node_t *phead NULL;create_node(phead);msg_t msg;// 收发数据char buff[128] {0};pid_t pid 0;pid fork();if (pid -1){perror(fork error);exit(-1);}else if (pid 0){// 子进程用于接收数据while (1){memset(msg, 0, sizeof(msg));if (-1 recvfrom(sockfd, msg, sizeof(msg), 0, (struct sockaddr *)clientaddr, clientaddr_len)){perror(recvfrom error);exit(-1);}printf(%s:%s\n, msg.name, msg.txt);switch (msg.type){case L:do_login(phead, msg, sockfd, clientaddr);break;case C:do_chat(phead, msg, sockfd, clientaddr);break;case Q:do_quit(phead, msg, sockfd, clientaddr);break;}}}else if (pid 0){// 父进程用于发送数据// 把父进程当做一个客户端 以群聊的方式 把系统消息发给子进程strcpy(msg.name, server);msg.type C;while (1){memset(msg.txt, 0, 128);fgets(msg.txt, sizeof(msg.txt), stdin);msg.txt[strlen(msg.txt) - 1] \0;if (-1 sendto(sockfd, msg, sizeof(msg), 0, (struct sockaddr *)serveraddr, serveraddr_len)){perror(sento error);exit(-1);}}}close(sockfd);return 0;
}void create_node(node_t **p)
{*p (node_t *)malloc(sizeof(node_t));memset(*p, 0, sizeof(node_t));
}
// 登录操作函数
void do_login(node_t *phead, msg_t msg, int sockfd, struct sockaddr_in clientaddr)
{// 遍历链表 当前在线的所有人发“***加入了群聊”的消息node_t *ptemp phead;while (ptemp-next ! NULL){ptemp ptemp-next;if (-1 sendto(sockfd, msg, sizeof(msg), 0, (struct sockaddr *)(ptemp-clientaddr), sizeof(ptemp-clientaddr))){perror(sento error);exit(-1);}}// 把新加入的群聊客户端网络信息结构体加入到链表中node_t *pnew NULL;create_node(pnew);pnew-clientaddr clientaddr;pnew-next phead-next;phead-next pnew;return;
}
void do_chat(node_t *phead, msg_t msg, int sockfd, struct sockaddr_in clientaddr)
{// 遍历链表 将群聊的消息 发给除了自己之外的所有人node_t *ptemp phead;while (ptemp-next ! NULL){ptemp ptemp-next;if (memcmp(clientaddr, (ptemp-clientaddr), sizeof(clientaddr)) ! 0){if (-1 sendto(sockfd, msg, sizeof(msg), 0, (struct sockaddr *)(ptemp-clientaddr), sizeof(ptemp-clientaddr))){perror(sento error);exit(-1);}}}return;
}
void do_quit(node_t *phead, msg_t msg, int sockfd, struct sockaddr_in clientaddr)
{// 把 xxx 退出群聊的消息 发给在线的除自己的所有人 并且将自己在链表中删除node_t *ptemp phead;while (ptemp-next ! NULL){if (memcmp(clientaddr, (ptemp-next-clientaddr), sizeof(clientaddr)) ! 0){if (-1 sendto(sockfd, msg, sizeof(msg), 0, (struct sockaddr *)(ptemp-next-clientaddr), sizeof(ptemp-next-clientaddr))){perror(sento error);exit(-1);}ptemp ptemp-next;}else{node_t *pdel ptemp-next;ptemp-next pdel-next;free(pdel);pdel NULL;}}return;
}
client.c
#include head.h
typedef struct _MSG
{char type; // 类型 L 登录 C 群聊 Q 退出char name[32];char txt[128];
} msg_t;int main(int argc, const char *argv[])
{// 入参合理性检查if (argc ! 3){printf(usage error:%s ip port...\n, argv[0]);exit(-1);}int sockfd 0;// 创建套接字if (-1 (sockfd socket(AF_INET, SOCK_DGRAM, 0))){perror(socket error);exit(-1);}// 填充服务器网络信息结构体struct sockaddr_in serveraddr;socklen_t serveraddr_len sizeof(serveraddr);memset(serveraddr, 0, sizeof(serveraddr));serveraddr.sin_family AF_INET;serveraddr.sin_addr.s_addr inet_addr(argv[1]);serveraddr.sin_port htons(atoi(argv[2]));msg_t msg;memset(msg, 0, sizeof(msg));printf(请输入用户名);fgets(msg.name, sizeof(msg.name), stdin);msg.name[strlen(msg.name) - 1] \0;msg.type L;strcpy(msg.txt, 加入群聊);if (-1 sendto(sockfd, msg, sizeof(msg), 0, (struct sockaddr *)serveraddr, serveraddr_len)){perror(sendto error);exit(-1);}// 收发数据char buff[128] {0};pid_t pid;pid fork();if (pid -1){perror(fork error);exit(-1);}else if (pid 0){// 子进程用于接收数据while (1){memset(msg, 0, sizeof(msg));if (-1 recvfrom(sockfd, msg, sizeof(msg), 0, NULL, NULL)){perror(recvfrom error);exit(-1);}printf(%s : %s\n, msg.name, msg.txt);}}else if(pid0){// //父进程 在终端获取数据 发给服务器while (1){memset(msg.txt, 0, sizeof(msg.txt));fgets(msg.txt, 128,stdin);msg.txt[strlen(msg.txt) - 1] \0;if (strcmp(msg.txt, quit) 0){msg.type Q;strcpy(msg.txt, 退出群聊);}else{msg.type C;}if (-1 sendto(sockfd, msg, sizeof(msg), 0, (struct sockaddr *)serveraddr, serveraddr_len)){perror(sendto error);exit(-1);}if (Q msg.type){// 父进程退出之前先给子进程发信号 杀死子进程kill(pid, SIGKILL);wait(NULL);break;}}}close(sockfd);return 0;
}