基于UDP的网络群聊聊天室
流程图
服务器
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#define ERR_MSG(msg) do{\
fprintf(stderr, "line:%d ", __LINE__);\
perror(msg);\
}while(0)
#define PORT 6666
#define IP "192.168.31.32"
typedef struct cli_msg
{
char type;
char name[20];
char text[128];
}Msg;
typedef struct node{
union{
struct sockaddr_in logcin;
int len;
};
struct node*next;
}seqlist;
int do_quit(struct sockaddr_in cin,Msg rcvbuf,seqlist*L,int sfd);
int do_chat(struct sockaddr_in cin,Msg rcvbuf,seqlist*L,int sfd );
int do_login(struct sockaddr_in cin,Msg rcvbuf,seqlist*L,int sfd);
void showlink(seqlist*L);
seqlist *Creatseqlist()
{
seqlist*L=(seqlist*)malloc(sizeof(seqlist));
if(NULL==L){
printf("创建链表失败\n");
return NULL;
}
L->len=0;
L->next=NULL;
return L;
}
seqlist*CommLinklistCreatNode()
{
seqlist*L=(seqlist*)malloc(sizeof(seqlist));
if(NULL==L){
printf("创建链表失败\n");
return NULL;
}
L->next=NULL;
return L;
}
int main(int argc, const char *argv[])
{
int sfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sfd < 0)
{
ERR_MSG("socket");
return -1;
}
printf("socket create success sfd=%d __%d__\n", sfd, __LINE__);
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(IP);
if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
ERR_MSG("bind");
return -1;
}
printf("bind success __%d__\n", __LINE__);
char buf[128] = "";
ssize_t res = 0;
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
seqlist *L=Creatseqlist();
if(L==NULL){
printf("创建链表失败\n");
return -1;
}
pid_t cpid = fork();
if(cpid > 0)
{
Msg rcvbuf;
while(1)
{
res = recvfrom(sfd, &rcvbuf, sizeof(rcvbuf), 0, (struct sockaddr*)&cin, &addrlen);
if(res < 0)
{
ERR_MSG("recvfrom");
return -1;
}
switch(rcvbuf.type)
{
case 'L':
do_login(cin,rcvbuf,L,sfd);
break;
case 'C':
do_chat(cin,rcvbuf,L,sfd);
break;
case 'Q':
do_quit(cin,rcvbuf,L,sfd);
break;
default:
printf("协议 %c 错误 __%s__ __%d__\n", rcvbuf.type, __FILE__, __LINE__);
}
}
}
else if(0 == cpid)
{
Msg sndbuf;
sndbuf.type = 'C';
strcpy(sndbuf.name,"server");
while(1){
bzero(sndbuf.text, sizeof(sndbuf.text));
fgets(sndbuf.text, sizeof(sndbuf.text), stdin);
sndbuf.text[strlen(sndbuf.text)-1] = '\0';
if(sendto(sfd, &sndbuf, sizeof(sndbuf), 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
ERR_MSG("sendto");
return -1;
}
}
}
else
{
ERR_MSG("fork");
return -1;
}
close(sfd);
return 0;
}
void showlink(seqlist*L)
{
seqlist*p=L;
for(int i=0;i<L->len;i++){
p=p->next;
}
}
int do_login(struct sockaddr_in cin,Msg rcvbuf,seqlist*L,int sfd )
{
seqlist*p=L;
printf("%s上线...\n",rcvbuf.name);
while(p->next!=NULL){
p=p->next;
if(sendto(sfd,&rcvbuf, sizeof(rcvbuf), 0, (struct sockaddr*)&(p->logcin), sizeof(p->logcin)) < 0)
{
ERR_MSG("sendto");
return -1;
}
}
seqlist *q=CommLinklistCreatNode();
if(NULL==q){
printf("创建普通节点失败\n");
return -1;
}
q->logcin=cin;
q->next=L->next;
L->next=q;
L->len++;
showlink(L);
return 0;
}
int do_chat(struct sockaddr_in cin,Msg rcvbuf,seqlist*L,int sfd )
{
seqlist*p=L;
printf("%s:%s\n",rcvbuf.name,rcvbuf.text);
while(p->next!=NULL){
p=p->next;
if(p->logcin.sin_port==cin.sin_port){
continue;
}
if(sendto(sfd,&rcvbuf, sizeof(rcvbuf), 0, (struct sockaddr*)&(p->logcin), sizeof(p->logcin)) < 0)
{
ERR_MSG("sendto");
return -1;
}
}
return 0;
}
int do_quit(struct sockaddr_in cin,Msg rcvbuf,seqlist*L,int sfd)
{
seqlist*q=L;
while(q->next!=NULL){
seqlist*ago=q;
q=q->next;
if(q->logcin.sin_port==cin.sin_port){
ago->next=q->next;
free(q);
}
}
seqlist*p=L;
printf("%s退出群聊\n",rcvbuf.name);
while(p->next!=NULL){
p=p->next;
if(sendto(sfd,&rcvbuf, sizeof(rcvbuf), 0, (struct sockaddr*)&(p->logcin), sizeof(p->logcin)) < 0)
{
ERR_MSG("sendto");
return -1;
}
}
return 0;
}
客户端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#define ERR_MSG(msg) do{\
fprintf(stderr, "line:%d ", __LINE__);\
perror(msg);\
}while(0)
#define PORT 6666
#define IP "192.168.31.32"
struct cli_msg
{
char type;
char name[20];
char text[128];
};
int main(int argc, const char *argv[])
{
int sfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sfd < 0)
{
ERR_MSG("socket");
return -1;
}
printf("socket create success sfd=%d __%d__\n", sfd, __LINE__);
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(IP);
printf("请输入名字>>>");
char name[20] = "";
scanf("%s", name);
getchar();
struct cli_msg sndbuf;
sndbuf.type = 'L';
strcpy(sndbuf.name, name);
if(sendto(sfd, &sndbuf, sizeof(sndbuf), 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
ERR_MSG("sendto");
return -1;
}
printf("发送登录信息成功\n");
ssize_t res = 0;
struct sockaddr_in rcvAddr;
socklen_t addrlen = sizeof(rcvAddr);
pid_t pid=fork();
if(pid==0){
while(1){
res = recvfrom(sfd, &sndbuf, sizeof(sndbuf), 0, (struct sockaddr*)&rcvAddr, &addrlen);
if(res < 0)
{
ERR_MSG("recvfrom");
return -1;
}
switch(sndbuf.type)
{
case 'L':
printf("%s上线...\n",sndbuf.name);
break;
case 'C':
printf("%s:%s\n",sndbuf.name,sndbuf.text);
break;
case 'Q':
printf("%s退出群聊\n",sndbuf.name);
break;
default:
printf("协议 %c 错误 __%s__ __%d__\n", sndbuf.type, __FILE__, __LINE__);
break;
}
}
}
else if(pid>0){
while(1){
sndbuf.type = 'C';
bzero(sndbuf.text, sizeof(sndbuf.text));
fgets(sndbuf.text, sizeof(sndbuf.text), stdin);
sndbuf.text[strlen(sndbuf.text)-1] = '\0';
if(strcmp(sndbuf.text,"quit")==0){
sndbuf.type = 'Q';
if(sendto(sfd, &sndbuf, sizeof(sndbuf), 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
ERR_MSG("sendto");
return -1;
}
break;
}
if(sendto(sfd, &sndbuf, sizeof(sndbuf), 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
ERR_MSG("sendto");
return -1;
}
}
}
else{
ERR_MSG("fork");
return -1;
}
close(sfd);
return 0;
}