使用UDP协议构建简易局域网内聊天室
实现功能:
客户端
1.开启时输入昵称并往服务器端发送带有客户端昵称
2.开启后能随时往服务器端发送聊天内容
3.收到服务器发来的数据时判别是否为自己发送的数据,若不是则输出num编号所指引的内容
4. 当输入quit时退出
服务器
1.接受各个客户端的信息,新用户则将其存入链表中并向各个用户发送有新用户加入的信息
2.当用户输入quit时,删除该用户信息并向各个用户发送该用户退出的信息
3.当收到正常聊天信息时发送给各个用户
代码
客户端
客户端中ip设定为本机的ip地址,通过外部传参传入不同的端口号用以区分不同用户
-
-
-
-
-
-
-
-
-
-
-
fprintf(stderr,"_%d_",__LINE__);\
-
perror(msg);\
-
}while(0)
-
-
//#define PORT 8888 // 1024~49151
-
typedef struct MSG{
-
int num;
-
char name[20];
-
char data[256];
-
}MSG;
-
-
int sfd;
-
struct sockaddr_in cin;
-
socklen_t addrlen= sizeof(cin);
-
MSG msg;
-
char cname[20];
-
void *shou(void*arg)
-
{
-
-
while(1)
-
{
-
-
if(recv(sfd, &msg, sizeof(msg),0) < 0)
-
{
-
ERR_MSG("recvfrom");
-
return NULL;
-
}
-
-
if (strcmp(msg.name,cname)!=0) //判断是否为自己发送的
-
{
-
if(msg.num==3)
-
{
-
printf("%s:%s\n",msg.name,msg.data);
-
}
-
if (msg.num==4)
-
{
-
printf("%s进入聊天室\n",msg.name);
-
}
-
}
-
-
}
-
pthread_exit(NULL);
-
-
}
-
-
-
-
void *fa(void*arg)
-
{
-
-
-
while(1)
-
{
-
-
scanf("%s",msg.data);
-
-
msg.num=2;
-
strcpy(msg.name,cname);
-
-
if(sendto(sfd, &msg, sizeof(msg), 0, (struct sockaddr*)&cin, sizeof(cin)) < 0)
-
{
-
ERR_MSG("recvfrom");
-
return NULL;
-
}
-
if (strcmp(msg.data,"quit")==0)
-
{
-
exit(0);
-
}
-
-
-
}
-
pthread_exit(NULL);
-
-
-
}
-
-
-
-
-
-
//绑定一个广播ip的端口试试
-
-
int main(int argc, const char *argv[])
-
{
-
-
//创建报式套接字
-
sfd =socket(AF_INET,SOCK_DGRAM,0);
-
if (sfd<0)
-
{
-
ERR_MSG("socket");
-
return -1;
-
}
-
printf("create socket success\n");
-
-
-
int broad =1;
-
if (setsockopt(sfd,SOL_SOCKET,SO_BROADCAST,&broad,sizeof(broad))<0)
-
{
-
ERR_MSG("setsockopt");
-
return -1;
-
}
-
-
-
//填充地址信息结构体,真实的地址信息结构体与协议族有关
-
//AF_INEt 详见 man 7 ip
-
struct sockaddr_in sin;
-
sin.sin_family =AF_INET;
-
sin.sin_port =htons(8888);//主机字节序转网络字节序的端口号
-
sin.sin_addr.s_addr = inet_addr("192.168.31.255");
-
cin = sin;
-
-
int port = atoi(argv[1]);
-
struct sockaddr_in bin;
-
bin.sin_family =AF_INET;
-
bin.sin_port =htons(port);//主机字节序转网络字节序的端口号
-
bin.sin_addr.s_addr = inet_addr(IP);
-
-
if(bind(sfd,(struct sockaddr*)&bin,sizeof(bin))==-1)
-
{
-
ERR_MSG("bind");
-
return -1;
-
}
-
-
ssize_t res=0;
-
-
printf("请输入用户名:");
-
scanf("%s",msg.name);
-
msg.num=1;//num为1时内容为名字
-
strcpy(cname,msg.name);
-
sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin, addrlen);
-
-
msg.num=2; //num为2时内容为聊天内容
-
-
//将客户端的收发分别写入两个线程,这样就可以同时运行
-
pthread_t tid1,tid2;
-
if (pthread_create(&tid1,NULL,shou,NULL)!=0)
-
{
-
ERR_MSG("pthread_create");
-
return -1;
-
}
-
-
if (pthread_create(&tid2,NULL,fa,NULL)!=0)
-
{
-
ERR_MSG("pthread_create");
-
return -1;
-
}
-
-
-
-
-
pthread_join(tid1,NULL);
-
pthread_join(tid2,NULL);
-
close(sfd);
-
-
-
-
return 0;
-
}
服务器端
-
-
-
-
-
-
-
-
-
-
-
fprintf(stderr,"_%d_",__LINE__);\
-
perror(msg);\
-
}while(0)
-
-
typedef struct MSG{
-
int num;
-
char name[20];
-
char data[256];
-
-
}MSG;
-
-
MSG msg;
-
int sfd;
-
struct sockaddr_in cin;
-
socklen_t addrlen= sizeof(cin);
-
-
typedef struct Node{
-
union{
-
int len;
-
struct sockaddr_in nin;
-
};
-
struct Node * next;
-
}List; //定义一个链表用于存放用户信息
-
-
-
-
-
-
-
-
int main(int argc, const char *argv[])
-
{
-
-
//创建报式套接字
-
sfd =socket(AF_INET,SOCK_DGRAM,0);
-
if (sfd<0)
-
{
-
ERR_MSG("socket");
-
return -1;
-
}
-
printf("create socket success\n");
-
-
int broad =1;
-
if (setsockopt(sfd,SOL_SOCKET,SO_BROADCAST,&broad,sizeof(broad))<0)
-
{
-
ERR_MSG("setsockopt");
-
return -1;
-
}
-
MSG msg;
-
-
//填充地址信息结构体,真实的地址信息结构体与协议族有关
-
//AF_INEt 详见 man 7 ip
-
struct sockaddr_in sin;
-
sin.sin_family =AF_INET;
-
sin.sin_port =htons(8888);//主机字节序转网络字节序的端口号
-
sin.sin_addr.s_addr = inet_addr("192.168.31.255");
-
if (bind(sfd,(struct sockaddr *)&sin,sizeof(sin))<0)
-
{
-
ERR_MSG("bind");
-
return -1;
-
}
-
-
-
List *l= (List*)malloc(sizeof(List));
-
if (NULL==l)
-
{
-
ERR_MSG("malloc");
-
return -1;
-
}
-
l->len=0;
-
l->next=NULL;
-
List * p =NULL;
-
List * q=NULL;
-
-
ssize_t res=0;
-
-
while (1)
-
{
-
res = recvfrom(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&cin,&addrlen);
-
if(res == -1)
-
{
-
ERR_MSG("recvfrom");
-
return -1;
-
}else if (res>0)//读取成功
-
{
-
if (msg.num==1)//新用户,需a要写入链表
-
{
-
printf("[%s:%d]\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));
-
//使用头插将新用户插入链表中
-
p= (List*)malloc(sizeof(List));
-
if (NULL==p)
-
{
-
ERR_MSG("malloc");
-
return -1;
-
}
-
-
p->next=l->next;
-
p->nin=cin;
-
l->next=p;
-
l->len ;
-
-
q=l->next;
-
//广播有新的用户进入聊天
-
msg.num=4;//防止自己收到后继续输出
-
while(q!=NULL)
-
{
-
if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&q->nin,sizeof(q->nin))<0)
-
{
-
ERR_MSG("sendto");
-
return -1;
-
}
-
q=q->next;
-
-
}
-
}else if(msg.num==2)//老用户
-
{
-
printf("[%s:%d]\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));
-
if (strcmp(msg.data,"quit")==0)//用户退出,需要广播退出信息并将其在链表中删除
-
{
-
msg.num=3;
-
strcpy(msg.data,"已退出");
-
q=l->next;
-
while(q!=NULL)
-
{
-
if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&q->nin,sizeof(q->nin))<0)
-
{
-
ERR_MSG("sendto");
-
return -1;
-
}
-
q=q->next;
-
-
}
-
p=l;
-
while (p->next!=NULL)
-
{
-
if (p->next->nin.sin_port == cin.sin_port)
-
{
-
q=p->next->next;
-
free(p->next);
-
p->next=q;
-
break;
-
}
-
p=p->next;
-
}//将该用户在链表中删除
-
-
-
}else
-
{//正常聊天广播收到的内容
-
msg.num =3;//防止自己收到后继续输出
-
q=l->next;
-
while(q!=NULL)
-
{
-
if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&q->nin,sizeof(q->nin))<0)
-
{
-
ERR_MSG("sendto");
-
return -1;
-
}
-
q=q->next;
-
}
-
}
-
}
-
}
-
}
-
close(sfd);
-
return 0;
-
}
运行测试 :
成功完成预计功能。
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgfcfic
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01