码迷,mamicode.com
首页 > 其他好文 > 详细

基于udp的局域网聊天室

时间:2015-12-11 15:06:57      阅读:222      评论:0      收藏:0      [点我收藏+]

标签:

需要实现功能如下:
1.服务器端功能如下:
     广播通知客服端登录/退出
     接受客服端发来的消息,广播给所有用户
     广播系统消息
2.客服端功能如下:
   接收服务器发来的消息并显示
   发送消息给服务器端
 
实现代码如下:
//***********服务端*******************

1
#include <head.h> 2 3 #define CLIENT_LOGIN 10 4 #define CLIENT_QUIT 20 5 #define CLIENT_TALK 30 6 #define SYSTEM_TALK 40 7 #define SYSTEM_QUIT 50 8 //#define CLIENT_PRIVATE 60 9 10 typedef struct 11 { 12 int msg_type; //消息类型 13 char client_name[20];//存放客户端用户名 14 char msg_buf[1024]; 15 //char peer_name[20]; 16 }msg_t; 17 18 //给套接字类型取一个别名 19 typedef struct sockaddr DATATYPE; 20 21 //创建节点 22 typedef struct node{ 23 DATATYPE data; //数据类型是struct sockaddr,即套接字结构的数据 24 //char client_name[20]; 25 struct node *next; 26 }LinkNode; 27 28 //用于线程的传参,因为线程构造函数只有一个参数,如果要传多个参数,可以构造一个结构体 29 typedef struct 30 { 31 int sockfd; 32 LinkNode *head; 33 }arg_t; 34 35 //创建空链表 36 LinkNode *create_empty_linklist() 37 { 38 LinkNode *head; 39 40 head = (LinkNode *)malloc(sizeof(*head)); 41 if(!head){ 42 fprintf(stderr,"%s : fail to malloc : %s\n",__FUNCTION__,strerror(errno)); 43 exit(EXIT_FAILURE); 44 } 45 head->next = NULL; 46 47 return head; 48 } 49 50 //链表的插入 51 int insert_linklist(LinkNode *head,DATATYPE data) 52 { 53 LinkNode *temp; 54 55 temp = (LinkNode *)malloc(sizeof(LinkNode)); 56 if(!temp){ 57 fprintf(stderr,"%s : fail to malloc : %s\n",__FUNCTION__,strerror(errno)); 58 exit(EXIT_FAILURE); 59 } 60 temp->data = data; 61 62 temp->next = head->next;//头插 head a 63 head->next = temp; // head temp a 64 65 return 0; 66 } 67 68 int find_linklist(LinkNode *head,DATATYPE data) 69 { 70 LinkNode *p; 71 72 for(p = head->next; p != NULL;p = p->next){ //遍历,p指针移动 73 74 if(memcmp(&(p->data),&data,sizeof(DATATYPE)) == 0){ // ??找到插入链表的套接字 75 return 1; 76 } 77 } 78 79 return 0; 80 } 81 82 //初始化服务端套接字 83 int init_udp_server_socket(const char *ip,const char *port) 84 { 85 int ret; 86 int sockfd; 87 struct sockaddr_in server_addr; 88 89 sockfd = socket(AF_INET,SOCK_DGRAM,0); 90 if(sockfd < 0){ 91 perror("Fail to socket"); 92 exit(EXIT_FAILURE); 93 } 94 95 server_addr.sin_family = AF_INET; 96 server_addr.sin_port = htons(atoi(port)); 97 server_addr.sin_addr.s_addr = inet_addr(ip); 98 ret = bind(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr)); //绑定服务端ip,port,结构体本 身不能直接强转
 99     if(ret < 0){                                                                                        100         perror("Fail to bind");                                                                         101         exit(EXIT_FAILURE);
102     }
103 
104     return sockfd;//返回填充好的套接字描述符
105 }
106 
107 //删除节点
108 int delete_linklist(LinkNode *head,DATATYPE data)
109 {
110     LinkNode *p;
111     LinkNode *q;
112 
113     p = head->next;
114     q = head;    
115     //          q p
116     //head 1 2 3 4 5 0
117     while(p != NULL){
118         if(memcmp(&(p->data),&data,sizeof(DATATYPE)) == 0){//遍历,找到删除的节点,则跳出循环
119             break;
120         }else{
121             p = p->next;//指针移动
122             q = q->next;
123         }    
124     }
125 
126     if(p != NULL){
127         q->next = p->next;//执行删除操作
128         free(p);
129     }
130 
131     return 0;
132 }
133 
134 //广播???
135 void broadcast_message(int sockfd,LinkNode *head,msg_t *pmsg,int len)
136 {
137     int n;
138     LinkNode *p = NULL;
139 
140     for(p = head->next; p != NULL;p = p->next)
141     {
142         n = sendto(sockfd,pmsg,len,0,&(p->data),sizeof(struct sockaddr));
143         if(n < 0){
144             perror("Fail to sendto");
145             exit(EXIT_FAILURE);
146         }
147     }
148 
149     return;
150 }
151 
152 //主机接收消息
153 void recv_udp_message(int sockfd,LinkNode *L)
154 {
155     int n;
156     msg_t msg;
157     struct sockaddr_in peer_addr;
158     socklen_t addrlen = sizeof(struct sockaddr);
159 
160     while(1)
161     {
162         n = recvfrom(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&peer_addr,&addrlen);
163         if(n < 0){
164             perror("Fail to recvfrom");
165             exit(EXIT_FAILURE);
166         }
167 
168         printf("--------------------------------------------\n");
169         printf("Ip   : %s\n",inet_ntoa(peer_addr.sin_addr));
170         printf("Port : %d\n",htons(peer_addr.sin_port));
171         printf("Recv %d bytes : %s\n",n,msg.msg_buf);
172         printf("--------------------------------------------\n");
173 
174         switch(msg.msg_type)
175         {
176         case CLIENT_LOGIN:
177             insert_linklist(L,*(struct sockaddr *)&peer_addr);
178             break;
179 
180         case CLIENT_QUIT:
181             delete_linklist(L,*(struct sockaddr *)&peer_addr);
182             break;
183 
184         case CLIENT_TALK:
185             break;
186         }
187         broadcast_message(sockfd,L,&msg,sizeof(msg));
188     }
189 
190     return ;
191 }
192 
193 //???子线程
194 void *send_udp_mssage(void *arg)
195 {
196     msg_t msg;
197     int sockfd = ((arg_t *)arg)->sockfd;
198     LinkNode *head = ((arg_t *)arg)->head;
199 
200     while(1)
201     {
202         printf("input>");
203         msg.msg_type = SYSTEM_TALK;
204         strcpy(msg.client_name,"system");
205 
206         fgets(msg.msg_buf,sizeof(msg.msg_buf),stdin);
207         msg.msg_buf[strlen(msg.msg_buf) - 1]= \0;         
208                                                                                            209       if(strncmp(msg.msg_buf,"quit",4) == 0)
211             goto next;
212 
213         broadcast_message(sockfd,head,&msg,sizeof(msg));    
214     }
215 
216 next:
217     msg.msg_type = SYSTEM_QUIT;
218     broadcast_message(sockfd,head,&msg,sizeof(msg));    
219     exit(EXIT_SUCCESS);
220 }
221 
222 //./udp_server  ip  port
223 int main(int argc, const char *argv[])
224 {
225     int ret;
226     int sockfd;
227     arg_t thread_arg;
228     pthread_t tid;
229     LinkNode *L = create_empty_linklist();
230 
231     if(argc < 3){
232         fprintf(stderr,"Usage : %s <ip> <port>\n",argv[0]);
233         return -1;
234     }
235 
236     sockfd = init_udp_server_socket(argv[1],argv[2]);
237 
238     thread_arg.sockfd = sockfd;
239     thread_arg.head   = L;
240     ret = pthread_create(&tid,NULL,send_udp_mssage,&thread_arg);//子线程负责发送消息
241 
242     recv_udp_message(sockfd,L);
243 
244     return 0;
245 }


//************客户端**************

1
#include <head.h> 2 3 #define CLIENT_LOGIN 10 4 #define CLIENT_QUIT 20 5 #define CLIENT_TALK 30 6 #define SYSTEM_TALK 40 7 #define SYSTEM_QUIT 50 8 9 typedef struct 10 { 11 int msg_type; 12 char client_name[20]; 13 char msg_buf[1024]; 14 }msg_t; 15 16 int init_udp_client_socket(const char *ip,const char *port) 17 { 18 int ret; 19 int sockfd; 20 struct sockaddr_in client_addr; 21 22 sockfd = socket(AF_INET,SOCK_DGRAM,0); 23 if(sockfd < 0){ 24 perror("Fail to socket"); 25 exit(EXIT_FAILURE); 26 } 27 28 if(ip != NULL && port != NULL){ 29 30 client_addr.sin_family = AF_INET; 31 client_addr.sin_port = htons(atoi(port)); 32 client_addr.sin_addr.s_addr = inet_addr(ip); 33 ret = bind(sockfd,(struct sockaddr *)&client_addr,sizeof(client_addr)); 34 if(ret < 0){ 35 perror("Fail to bind"); 36 exit(EXIT_FAILURE); 37 } 38 } 39 40 return sockfd; 41 } 42 43 void send_udp_message(int sockfd,const char *peer_ip,const char *peer_port,const char *client_name) 44 { 45 int n; 46 msg_t msg; 47 struct sockaddr_in peer_addr; 48 socklen_t addrlen = sizeof(struct sockaddr); 49 50 peer_addr.sin_family = AF_INET; 51 peer_addr.sin_port = htons(atoi(peer_port)); 52 peer_addr.sin_addr.s_addr = inet_addr(peer_ip); 53 54 //send login message 55 msg.msg_type = CLIENT_LOGIN; 56 strcpy(msg.client_name,client_name); 57 strcpy(msg.msg_buf,"I am login!"); 58 59 n = sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&peer_addr,addrlen); 60 if(n < 0){ 61 perror("Fail to sendto"); 62 exit(EXIT_FAILURE); 63 } 64 65 while(1) 66 { 67 printf("input>"); 68 msg.msg_type = CLIENT_TALK; 69 70 fgets(msg.msg_buf,sizeof(msg.msg_buf),stdin); 71 msg.msg_buf[strlen(msg.msg_buf) - 1]= \0; 72 73 n = sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&peer_addr,addrlen); 74 if(n < 0){ 75 perror("Fail to sendto"); 76 exit(EXIT_FAILURE); 77 } 78 79 printf("Send %d bytes : %s\n",n,msg.msg_buf); 80 81 if(strncmp(msg.msg_buf,"quit",4) == 0) 82 break; 83 } 84 85 return ; 86 } 87 88 void thread_recv_udp_message(void *arg) 89 { 90 int n; 91 msg_t msg; 92 int sockfd = *(int *)arg; 93 struct sockaddr_in peer_addr; 94 socklen_t addrlen = sizeof(struct sockaddr); 95 96 while(1) 97 { 98 n = recvfrom(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&peer_addr,&addrlen); 99 if(n < 0){ 100 perror("Fail to recvfrom"); 101 exit(EXIT_FAILURE); 102 } 103 104 printf("--------------------------------------------\n"); 105 printf("Ip : %s\n",inet_ntoa(peer_addr.sin_addr)); 106 printf("Port : %d\n",htons(peer_addr.sin_port)); 107 printf("Recv %d bytes : %s\n",n,msg.msg_buf); 108 printf("--------------------------------------------\n"); 109 110 if(msg.msg_type == SYSTEM_QUIT){ 111 exit(EXIT_SUCCESS); 112 } 113 } 114 115 return ; 116 } 117 118 //./udp_client server_ip server_port client_name 119 int main(int argc, const char *argv[]) 120 { 121 int sockfd; 122 int ret; 123 pthread_t tid; 124 125 if(argc < 4){ 126 fprintf(stderr,"Usage : %s <server_ip> <server_port> <client_name>\n",argv[0]); 127 return -1; 128 } 129 130 131 sockfd = init_udp_client_socket(NULL,NULL); 132 //sockfd = init_udp_client_socket("192.168.0.137","9999"); 133 134 //create a thread for udp socket to recv message 135 ret = pthread_create(&tid,NULL,thread_recv_udp_message,&sockfd); 136 if(ret != 0){ 137 fprintf(stderr,"Fail to pthread_create : %s\n",strerror(ret)); 138 exit(EXIT_FAILURE); 139 } 140 141 send_udp_message(sockfd,argv[1],argv[2],argv[3]); 142 143 return 0; 144 }

 

 
 
 

基于udp的局域网聊天室

标签:

原文地址:http://www.cnblogs.com/yuanxuya/p/5038830.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!