UDP局域网聊天室实现
//链表的结点数据 //typedef struct sockaddr_in data_t;// //typedef int data_t; typedef struct {
struct sockaddr_in addr;//客户端地址 char name[20];//客户端名字 }data_t;
//链表的结点类型 typedef struct _node_ {
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <strings.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/wait.h> #include <signal.h>
for(i = 0;i < 10;i++) {
insert_head_linklist(head,i); }
print_linklist(head);
delete_assign_node(head,3);
print_linklist(head);
return 0; } #endif
//3.服务器端
#ifdef _DEB_ puts("==============broadcast==================="); printf("Ip:\t%s\n",inet_ntoa(p->data.sin_addr)); printf("Port:\t%d\n",ntohs(p->data.sin_port)); printf("Info:\t%s\n",pmsg->mtext); puts("==========================================");
/*while(p->next && p->next->data != data)*/ while(p->next && (memcmp(&p->next->data,&data,sizeof(data)) != 0)) {
p = p->next; }
if(p->next == NULL) {
return -1; }
#endif
p = p->next; }
给指定的客户端发送消息 参数:
@serfd 进行通信的socket对应的文件描述符 @head 链表的头指针 @pmsg 指定的客户端的名字 返回值: 0 成功 -1 表示没有找到对应的客户端
2.broadcast_all_client(int serfd,Linklist *head,msg_t *pmsg); 功能:实现对每个客户端发送消息
参数:同上 返回值:
0 成功
3.struct sockaddr_in *find_assign_client(Linklist *head,char *name); 功能: 从链表中查找对应名字的客户端,找到之后返回其地址信息
3.UDP聊天功能实现(群聊,私聊) //1.头文件
#ifndef _HEAD_H_ #define _HEAD_H_
1.UDP中如果向某个客户端发送消息,那么我们需要指定对端的地址信息(ip+port)的信息 那么服务器端如何保留这些客户端的信息就是我们需要关注的问题? 想想看如何可以实现?。。。。。。balabala 那么我们这里就用的非常广泛的一种数据结构,链表来实现对 客户端地址信息的保留。 链表的特点,就不需要说了。我们这里主要关注其 可以动态增长的特点来使用 那么这一问题解决之后,我们要做的就是实现相关的数据结构的操作。
temp->next = head->next; head->next = temp;
return 0; }
int delete_assign_node(linklist_t head,data_t da_t *temp = NULL;
temp = p->next; p->next = temp->next; free(temp); temp = NULL;
return 0; }
#if 0 int print_linklist(linklist_t head) {
linknode_t *p = head->next;
while(p) {
那么我们分析一下该链表的数据结构构建。 数据结构 地址信息节点:
typedef struct node { struct sockaddr_in addr; struct node *next;
} data_t;
//消息类型
#define CLIENT_TALK 100 #define SERVER_TALK 200
} } } else if (pid == 0)//子进程,主要功能,数据接收 {
while (1) { 1.接收数据 2.显示数据
}
}
分析"服务器端"的流程:
整体的流程是 UDP的网络服务器的 基本编程
socket bind pid = fork(); if (pid >0)//父进程 发数据,系统级别的消息,给所有客户端发送消息 {
1.从键盘获得数据 2.发送给服务器自己
} else if (pid == 0) //子进程,接收数据,处理消息 {
1.接收发过来的消息 2.根据消息类型进行处理 a.登录消息 b.退出消息 d.群聊消息 这三类消息都需要给每个客户端发送
e.私聊消息 需要进行指定聊天对象 }
分析数据结构体:
首先我们要考虑一个服务器端的程序如何给每个客户端依次发送消息?
#include "head.h"
int broadcase_to_client(int sockfd,linklist_t addrlist,msg_t *pmsg) {
linknode_t *p = addrlist->next;
while(p) {
if(strncmp(pmsg->src_name,p->,20) != 0) //不给自己回发消息 sendto(sockfd,pmsg,sizeof(msg_t),0,(sa_t *)&p->data.addr,sizeof(sa_t)); /*printf("msg.mtext = %s\n",msg.mtext);*/
分析客户端的流程:
客户端: 整体的流程首先是 网络的基本编程
socket pid = fork(); if (pid > 0) //父进程,主要功能,数据发送 {
while (1) { //大循环 1.发送一个登录的消息,告诉大家我上线了 2..从键盘获得数据 a.聊天的对端的名字 SYSTERM 群聊消息 非SYSTERM 私聊消息 c.聊天的内容 d.输入quit时,结束 3.聊天结束,发送一个聊天结束的消息给大家,告诉大家说我下线了
#endif
//2.链表操作的函数实现
#include "head.h"
linklist_t create_empty_linklist() {
linknode_t *head = NULL;
head = (linknode_t *)malloc(sizeof(linknode_t)); head->next = NULL;
char mtext[BUF_SZ];//消息正文
} msg_t;
分析函数实现:
服务器端:
1.int send_assign_client(int serfd,Linklist *head,msg_t *pmsg); 功能:
通过名字查找对应的客户端是否存在,存在则发送消息 不存在返回出错信息表示客户端不存在
return head; }
int insert_head_linklist(linklist_t head,data_t data) {
linknode_t *temp = NULL;
temp = (linknode_t *)malloc(sizeof(linknode_t)); temp->data = data;
printf("%-4d",p->data); p = p->next; } putchar('\n');
return 0; }
int main(int argc, const char *argv[]) {
linklist_t head = NULL; int i = 0;
head = create_empty_linklist();
//私聊 + client name //给所有客户端发送
#define CLIENT_LOGIN 300 //有客户端登陆,地址存入链表 #define CLIENT_LOGOUT 400 //有客户端退出,地址从链表删除
//消息结构体 typedef struct {
long type;//消息类型 char src_name[20];//自己客户端名字,在运行客户端命令行指定名字 char dst_name[20];//对方客户端名字,在运行客户端命令行指定名字 //客户端登陆时给服务器发自己的名字和地址,/*{{{*/ //私聊时客户端用于指定对方名字,在服务器端可以根据名字找到对应对方的地址 //服务器端转发私聊消息时如果要知道是谁发送,根据地址在链表中查找名字/*}}}*/