服务器:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<netinet/in.h>
#include<pthread.h>
#define IP "192.168.10.113"
#define PORT 6666
#define ERR_MSG(msg)do{\
printf("line:%d\n",__LINE__);\
perror("msg");\
}while(0)
//创建客户端输入信息结构体
struct cli_info
{
char username[30];
struct sockaddr_in cin;
};
//创建结构体链表
typedef struct Node
{
union
{
int len;
struct cli_info info;
};
struct Node*next;
};*linklist;
void*callback(void*arg);
int main(int argc, const char *argv[])
{
//创建套接字
int sfd=socket(AF_INET,SOCK_DGRAM,0)
if(sfd<0)
{
ERR_MSG("socket");
return -1;
}
//服务器的IP
struct sockaddr_in sin;
sin.sin_family =AF_INET;
sin.sin_PORT =htons(PORT);
sin.sin_addr.s_addr =inet_addr(IP);
//绑定服务器的端口和IP
if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR_MSG("bind");
return -1;
}
printf("bind create success\n");
//创建线程,分支线程向客户端发送消息,主线程接受客户端消息
pthread_t tid;
linklist L=linklist_create(1);
if(pthread_create(&tid,NULL,callback,L)<0)
{
ERR_MSG("pthread_create");
return -1;
}
//分离线程
pthread_detach(tid);
//存储客户端信息
struct sockaddr_in cin;
ssize_t len=sizeof(cin);
char buf[512]="";
ssize_t res=0;
struct cli_info info;
linklist p=L;
ssize_t addrlen=sizeof(cin);
while(1)
{
bzero(buf,sizeof(buf));
res=recvfrom(sfd,buf,sizeof(buf),(struct sockaddr*)&cin,&addrlen);
if(res<0)
{
ERR_MSG("recvfrom");
return -1;
}
if(buf[0]==1)
{
//客户端登录
//判断是否有重复
strcpy(info.username,buf+1);
info.cin=cin;
//向所有人发送消息
p=L;
buf[0]=3;
sprintf(buf+strlen(buf)+1,"-----上线了---------",info.username);
while(p->next)
{
p=p->next;
sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&(p->info.cin),addrlen);
}
printf("[%s %d]:用户%s下线\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_PORT),info.username);
}
else if(buf[0]==2)
{
//客户端下线
strcpy(info.username,buf+1);
//将该用户信息删除
linklist_delete(L,info.username);
//向所有人发送消息
p=L;
buf[0]=3;
sprintf(buf+strlen(buf)+1,"-----下线了---------",info.username);
while(p->next)
{
p=p->next;
sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&(p->info.cin),addrlen);
}
printf("[%s %d]:用户%s下线\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_PORT),info.username);
}
else if(buf[0]==3)
{
//客户端消息
strcpy(info.username,buf+1);
p=L;
while(p->next)
{
p=p->next;
//不给发消息的人的发送
if(strcmp(info.username,p->info.username)!=0)
{
sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&(p->info.username),addrlen);
}
printf("[%s %d]:%s %s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_PORT),buf+1,buf+strlen(buf)+1);
}
}
close(sfd);
}
return 0;
}
void*callback(void *arg)
{
char buf[512]="";
linklist L=(linklist)arg;
linklist p=L;
int len=0;
char *ptr=NULL;
while(1)
{
bzero(buf,sizeof(buf));
buf[0]=3;
strcpy(buf+1,"系统消息");
len=strlen(buf)+1;
ptr=buf+len;
fgets(buf,sizeof(buf)-len,stdin);
buf[strlen(ptr)+len-1]=0;
p=L;
while(p->next)
{
p=p->next;
sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&(p->info.cin),sizeof(p->info.cin));
}
printf("系统信息发送成功:%s\n",ptr);
}
}
//创建链表 1为头结点 0为普通节点
linklist linklist_create(int flag)
{
linklist L=(linklist)malloc(sizeof(struct Node));
if(L==NULL)
{
return NULL;
}
if(flag==1)
{
//头节点的数据域
L->len=0;
//头节点的指针域
L->next=NULL;
return L;
}
}
//链表头插
int linklist insertbyhead(linklist L,struct cli_info info)
{
if(L==NULL)
return -1;
linklist p=L;
while(p->next)
{
//指针域
p=p->next;
//数据域
L->next=p->next;
free(p);
p=NULL;
L->len--;
}
return 0;
}
//链表头删
int linklist deletebyhead(linklist L,char *username)
{
if(L==NULL|L->next==NULL)
{
return -1;
}
linklist p=L;
while(p->next)
{
//指针域
p=p->next;
//数据域
L->next=p->next;
free(p);
L->len--;
}
return 0;
}
//链表指定元素删除
int linklist_delete(linklist L,char*username)
{
if(L==NULL|L->next==NULL)
{
return -1;
}
linklist p=L;
while(p->next)
{
if(strcmp(username,p->next->info.username)==0)
{
linklist q=p->next;
p-next=q->next;
free(q);
q=NULL;
L->len--;
return 0;
}
p=p->next;
}
printf("删除失败,没有该用户\n");
return -1;
}
//释放链表
linklist free_space(linklist L)
{
if(L==NULL)
{
return -1;
while(L->next)
{
linklist_deletebyhead(L);
}
free(L);
L=NULL;
return NULL;
}
}
客户端:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <pthread.h>
#define ERR_MSG(msg) do{\
printf("__%d__\n", __LINE__);\
perror(msg);\
} while(0)
#define IP "192.168.10.113"
#define SER_PORT 6666
void *callback(void *arg);
int main(int argc, const char *argv[])
{
//创建报式套接字
int sfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sfd < 0)
{
ERR_MSG("socket");
return -1;
}
struct sockaddr_in sin;
socklen_t addrlen = sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(IP);
char usrname[24] = "";
printf("请输入用户名>>>\n");
fgets(usrname, sizeof(usrname), stdin);
usrname[strlen(usrname)-1] = 0;
//发送登录请求包
char buf[512] = "";
sprintf(buf, "%c%s%c", 1, usrname, 0);
if(sendto(sfd, buf, strlen(buf)+1, 0, (struct sockaddr*)&sin, addrlen) < 0)
{
ERR_MSG("sendto");
return -1;
}
//创建一个分支线程接收服务器消息,主线程向服务器发送消息
pthread_t tid;
if(pthread_create(&tid, NULL, callback, &sfd) < 0)
{
ERR_MSG("pthread_create");
return -1;
}
//分离线程
pthread_detach(tid);
int len = strlen(buf) + 1; //消息内容前的长度
char *ptr = buf + len; //消息内容起始地址
while(1)
{
//主线程向服务器发送消息
bzero(ptr, sizeof(buf)-len);
fgets(ptr, sizeof(buf)-len, stdin);
buf[strlen(ptr)-1+len] = 0;
if(strcasecmp(ptr, "quit") == 0)
{
buf[0] = 2;
if(sendto(sfd, buf, strlen(buf)+1, 0, (struct sockaddr*)&sin, addrlen) < 0)
{
ERR_MSG("sendto");
return -1;
}
break;
}
else
{
buf[0] = 3;
if(sendto(sfd, buf, sizeof(buf), 0, (struct sockaddr*)&sin, addrlen) < 0)
{
ERR_MSG("sendto");
return -1;
}
}
}
if(close(sfd) < 0)
{
ERR_MSG("close");
return -1;
}
return 0;
}
void *callback(void *arg)
{
int sfd = *(int *)arg;
char buf[512] = "";
ssize_t res = 0;
while(1)
{
bzero(buf, sizeof(buf));
res = recv(sfd, buf, sizeof(buf), 0);
if(res < 0)
{
ERR_MSG("recv");
return NULL;
}
if(buf[0] == 3)
{
printf("%s: %s\n", buf+1, buf+strlen(buf)+1);
}
}
}