C語(yǔ)言利用UDP實(shí)現(xiàn)群聊聊天室的示例代碼
1.UDP群聊的功能
有新用戶登錄,其他在線的用戶可以收到登錄信息
有用戶群聊,其他在線的用戶可以收到群聊信息
有用戶退出,其他在線的用戶可以收到退出信息
服務(wù)器可以發(fā)送系統(tǒng)信息
2.寫(xiě)項(xiàng)目的流程
畫(huà)流程圖
根據(jù)流程圖寫(xiě)框架
一個(gè)功能一個(gè)功能實(shí)現(xiàn)
3.流程圖

4.代碼實(shí)現(xiàn)
4.1頭文件
#ifndef __MYHEAD_H__
#define __MYHEAD_H__
#include <head.h>
#define N 512
//聊天操作用的結(jié)構(gòu)體
typedef struct _MSG{
char ch;//用來(lái)'l'聊天,'q'退出,'登錄d'
char name[128];//存名字
char text[N];//存聊天內(nèi)容
}msg_t;
//用來(lái)保存每個(gè)用戶信息的結(jié)構(gòu)體
typedef struct _Jilu{
struct sockaddr_in addr;
struct _Jilu *next;
}jilu_t;
int create_head(jilu_t **head);
int input_addr(jilu_t *head,msg_t msg,int sockfd,struct sockaddr_in clientaddr,socklen_t clientaddr_len);
int wx_addr(jilu_t *head,msg_t msg,int sockfd,struct sockaddr_in clientaddr,socklen_t clientaddr_len);
int tuichu_addr(jilu_t *head,msg_t msg,int sockfd,struct sockaddr_in clientaddr,socklen_t clientaddr_len);
#endif
4.2函數(shù)
#include "myhead.h"
//創(chuàng)建一個(gè)單鏈表頭
int create_head(jilu_t **head)
{
if(head==NULL){
printf("傳送錯(cuò)誤,請(qǐng)檢查\n");
return -1;
}
(*head)=(jilu_t *)malloc(sizeof(jilu_t));
(*head)->next=NULL;
return 0;
}
//記錄登錄的用戶的信息
int input_addr(jilu_t *head,msg_t msg,int sockfd,struct sockaddr_in clientaddr,socklen_t clientaddr_len)
{
if(head==NULL){
printf("傳送錯(cuò)誤,請(qǐng)檢查\n");
return -1;
}
//將這個(gè)用戶登錄的信息發(fā)送給所有人
snprintf(msg.text,sizeof(msg.text),"[%s]%s",msg.name,"登錄了");
//這個(gè)用來(lái)記錄頭的地址
jilu_t *jilu_head=head;
while(jilu_head->next!=NULL){
jilu_head=jilu_head->next;
if(sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&jilu_head->addr,clientaddr_len)==-1){
ERRLOG("將用戶登錄信息發(fā)給所有人失敗");
}
}
//創(chuàng)建一個(gè)新的節(jié)點(diǎn),并且把新的用戶信息放入新得單列表
jilu_t *temp=NULL;
create_head(&temp);
temp->addr=clientaddr;
//用頭插法將用戶信息插入鏈表
temp->next=head->next;
head->next=temp;
return 0;
}
int wx_addr(jilu_t *head,msg_t msg,int sockfd,struct sockaddr_in clientaddr,socklen_t clientaddr_len)
{
if(head==NULL){
printf("傳送錯(cuò)誤,請(qǐng)檢查\n");
return -1;
}
//將接受到的消息發(fā)給除了自己以外的所有人
jilu_t *jilu_head=head;
while(jilu_head->next!=NULL){
jilu_head=jilu_head->next;
if(0!=memcmp(&(jilu_head->addr),&clientaddr,sizeof(clientaddr))){
if(sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&jilu_head->addr,clientaddr_len)==-1){
ERRLOG("將聊天內(nèi)容發(fā)給所有人失敗");
}
}
}
return 0;
}
int tuichu_addr(jilu_t *head,msg_t msg,int sockfd,struct sockaddr_in clientaddr,socklen_t clientaddr_len)
{
if(head==NULL){
printf("傳送錯(cuò)誤,請(qǐng)檢查\n");
return -1;
}
snprintf(msg.text,sizeof(msg.text),"%s%s",msg.name,"退出登錄");
jilu_t *jilu_head=head;
jilu_t *pdel=NULL;
while(jilu_head->next!=NULL){
if(0==memcmp(&(jilu_head->next->addr),&clientaddr,sizeof(clientaddr))){
pdel=jilu_head->next;
jilu_head->next=pdel->next;
free(pdel);
pdel=NULL;
}else{
jilu_head=jilu_head->next;
if(sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&jilu_head->addr,clientaddr_len)==-1){
ERRLOG("將這個(gè)退出的信息告訴所有人失敗");
}
}
}
return 0;
}4.3服務(wù)器
#include "myhead.h"
int main(int argc, char const *argv[])
{
int sockfd=0;
pid_t pid=0;
msg_t msg;//用來(lái)進(jìn)行各種操作
msg_t faso;//用來(lái)發(fā)系統(tǒng)消息
if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1){
ERRLOG("創(chuàng)建服務(wù)器套接字失敗");
}
//將網(wǎng)絡(luò)信息結(jié)構(gòu)體放入服務(wù)器中
struct sockaddr_in serveraddr;
memset(&serveraddr,0,sizeof(serveraddr));
serveraddr.sin_family=AF_INET;
serveraddr.sin_port=htons(atoi(argv[2]));
serveraddr.sin_addr.s_addr=inet_addr(argv[1]);
socklen_t serveraddr_len=sizeof(serveraddr);
//將套接字與網(wǎng)絡(luò)信息結(jié)構(gòu)體綁定
if(bind(sockfd,(struct sockaddr*)&serveraddr,serveraddr_len)==-1){
ERRLOG("將套接字與網(wǎng)絡(luò)信息結(jié)構(gòu)體綁定失敗");
}
//創(chuàng)建一個(gè)新的網(wǎng)絡(luò)信息結(jié)構(gòu)體來(lái)存客戶端的信息
struct sockaddr_in clientaddr;
clientaddr.sin_family=AF_INET;
socklen_t clientaddr_len=sizeof(clientaddr);
//創(chuàng)建進(jìn)程
pid=fork();
if(pid==-1){
ERRLOG("服務(wù)器創(chuàng)建進(jìn)程失敗");
}else if(pid==0){
//創(chuàng)建一個(gè)單列表保存網(wǎng)絡(luò)信息結(jié)構(gòu)體
jilu_t *head;
create_head(&head);
memset(&msg,0,sizeof(msg));
while(1){
if(recvfrom(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&clientaddr,&clientaddr_len)==-1){
ERRLOG("接受客戶端傳來(lái)的信息失敗");
}
switch(msg.ch){
case 'd'://登錄信息
input_addr(head,msg,sockfd,clientaddr,clientaddr_len);
//head->next=NULL; //這個(gè)用來(lái)測(cè)試用的
break;
case 'l'://聊天信息
wx_addr(head,msg,sockfd,clientaddr,clientaddr_len);
break;
case 'q'://退出信息
tuichu_addr(head,msg,sockfd,clientaddr,clientaddr_len);
break;
}
}
}else{
while(1){
//發(fā)系統(tǒng)消息
memset(&faso,0,sizeof(faso));
fgets(faso.text,sizeof(faso.text),stdin);
faso.text[strlen(faso.text)-1]='\0';
faso.ch='l';
sprintf(faso.name,"%s","系統(tǒng)消息");
if(sendto(sockfd,&faso,sizeof(faso),0,(struct sockaddr*)&serveraddr,serveraddr_len)==-1){
ERRLOG("發(fā)送系統(tǒng)消息失敗");
}
}
}
return 0;
}4.4客戶端
#include "myhead.h"
int main(int argc, char const *argv[])
{
//判斷輸入的對(duì)不對(duì)
if(argc!=3){
printf("輸入格式錯(cuò)誤,./a.out ip port\n");
exit(EXIT_SUCCESS);
}
int sockfd=0;
pid_t pid=0;
msg_t msg;//創(chuàng)建發(fā)送用戶的信息
if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1){
ERRLOG("創(chuàng)建客戶端套接字失敗");
}
//將客戶端網(wǎng)絡(luò)信息結(jié)構(gòu)體進(jìn)行綁定
struct sockaddr_in clientaddr;
memset(&clientaddr,0,sizeof(clientaddr));
clientaddr.sin_family=AF_INET;
clientaddr.sin_port=htons(atoi(argv[2]));
clientaddr.sin_addr.s_addr=inet_addr(argv[1]);
socklen_t clientaddr_len=sizeof(clientaddr);
//輸入用戶的姓名進(jìn)行登錄操作
msg.ch='d';
printf("請(qǐng)輸入你用來(lái)登錄的姓名");
fgets(msg.name,sizeof(msg.name),stdin);
msg.name[strlen(msg.name)-1]='\0';
//給服務(wù)器發(fā)送用戶已經(jīng)登錄上的操作
if(sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&clientaddr,clientaddr_len)==-1){
ERRLOG("客戶端給服務(wù)器發(fā)送的登錄信息失敗");
}
//創(chuàng)建進(jìn)程,子進(jìn)程用來(lái)接受,父進(jìn)程用來(lái)發(fā)送
pid=fork();
if(pid==-1){
ERRLOG("客戶端創(chuàng)建進(jìn)程失敗");
}else if(pid==0){
//用來(lái)接受服務(wù)器發(fā)來(lái)的消息
while(1){
memset(&msg,0,sizeof(msg));
if(recvfrom(sockfd,&msg,sizeof(msg),0,NULL,NULL)==-1){
ERRLOG("接受服務(wù)器發(fā)來(lái)的信息錯(cuò)誤");
}
printf("[%s]>>(%s)\n",msg.name,msg.text);
}
}else{
//寫(xiě)入要判聊天的內(nèi)容
while(1){
memset(msg.text,0,sizeof(msg.text));
fgets(msg.text,sizeof(msg.text),stdin);
msg.text[strlen(msg.text)-1]='\0';
if(strncmp("quit",msg.text,5)==0){
msg.ch='q';
}else{
msg.ch='l';
}
//將寫(xiě)好的內(nèi)容發(fā)送給服務(wù)器
if(sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&clientaddr,clientaddr_len)==-1){
ERRLOG("將聊天內(nèi)容發(fā)送給服務(wù)器失敗");
}
//當(dāng)識(shí)別到停止的時(shí)候,關(guān)閉進(jìn)程
if(strncmp("quit",msg.text,5)==0){
kill(pid,SIGKILL);
close(sockfd);
exit(EXIT_SUCCESS);
}
}
}
return 0;
}到此這篇關(guān)于C語(yǔ)言利用UDP實(shí)現(xiàn)群聊聊天室的示例代碼的文章就介紹到這了,更多相關(guān)C語(yǔ)言 UDP聊天室內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)萬(wàn)年歷小程序
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)萬(wàn)年歷小程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-10-10
C語(yǔ)言實(shí)現(xiàn)最簡(jiǎn)單的剪刀石頭布小游戲示例
這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)最簡(jiǎn)單的剪刀石頭布小游戲,涉及C語(yǔ)言數(shù)組、隨機(jī)數(shù)與數(shù)值運(yùn)算等相關(guān)操作技巧,需要的朋友可以參考下2017-09-09
C++ Boost Container庫(kù)示例詳細(xì)講解
Boost是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱。Boost庫(kù)是一個(gè)可移植、提供源代碼的C++庫(kù),作為標(biāo)準(zhǔn)庫(kù)的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開(kāi)發(fā)引擎之一,是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱2022-11-11
C語(yǔ)言實(shí)現(xiàn)查詢自動(dòng)售貨機(jī)中的商品價(jià)格【實(shí)例分享】
本文主要介紹了C語(yǔ)言實(shí)現(xiàn)查詢自動(dòng)售貨機(jī)中的商品價(jià)格的相關(guān)資料。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-04-04

