#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/wait.h>
#include <semaphore.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/times.h>
#include <sys/select.h>
#include <sqlite3.h>
#include <poll.h>
int main(int argc, const char *argv[])
{
//创建套接字
int sfd = socket(AF_INET,SOCK_DGRAM,0);
if(sfd == -1)
{
perror("socket error");
return -1;
}
printf("套接字创建成功! sfd = %d\n",sfd);
//端口号快速重用
int reuse = -1;
if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))==-1)
{
perror("setsockopt error");
return -1;
}
printf("端口号快速重用成功! \n");
//绑定
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(SER_PORT);
sin.sin_addr.s_addr = inet_addr(SER_IP);
if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))==-1)
{
perror("bind error");
return -1;
}
printf("绑定成功\n");
//数据收发
struct sockaddr_in cin;
socklen_t socklen = sizeof(cin);
//创建一个用于检测文件描述符的容器
struct pollfd pfds[2];
pfds[0].fd = sfd; //表示第一个元素检测0号文件描述符
pfds[0].events = POLLIN; //要检测0号文件描述符的读事件
pfds[1].fd = 0; //表示第一个元素检测0号文件描述符
pfds[1].events = POLLIN; //要检测0号文件描述符的读事件
int res = -1;
struct usr usr_arr[1024] = {0};
struct cli_msg cli;
char wbuf[128]="";
char buf[128]="";
int i = 0;
while(1)
{
res = poll(pfds,2,-1); //阻塞检测文件描述符集合中是否有事件产生
if( res == 0)
{
printf("time out\n");
return -1;
}else if(res == -1)
{
perror("poll error");
return -1;
}
jixu:
//读事件
if(pfds[0].revents == POLLIN)
{
recvfrom(sfd,(struct cli_msg*)&cli,sizeof(cli),0,(struct sockaddr*)&cin,&socklen);
//判断消息类型
if(cli.type == 1)
{
int k=0;
int a=1;
//遍历数组将消息判断用户是否重复并发回判断结果
while(k<i)
{
if(strcmp(usr_arr[k].usrname,cli.usrname)==0)
{
strcpy(buf,"1");
sendto(sfd,&buf,sizeof(buf),0,(struct sockaddr*)&cin,sizeof(cin));
goto jixu;
}else
{
k++;
}
}
strcpy(buf,"2");
sendto(sfd,&buf,sizeof(buf),0,(struct sockaddr*)&cin,sizeof(cin));
//客户端ID和地址信息存入
strcpy(usr_arr[i].usrname,cli.usrname);
usr_arr[i].cin = cin;
printf("--------------------%s已上线--------------------\n",usr_arr[i].usrname);
i+=1;
}
else if(cli.type == 2)
{
int l = 0;
int a ;
printf("%s:%s\n",cli.usrname,cli.msgText);
if(strcmp(cli.msgText,"quit")==0)
{
for(l=0;l<i;l++)
{
if(cin.sin_port == usr_arr[l].cin.sin_port)
{
printf("--------------------%s已下线--------------------\n",usr_arr[l].usrname);
for(a=l;a<i;a++)
{
usr_arr[a]=usr_arr[a+1];
}
i--;
goto jixu;
}
}
}
for(int j=0;j<i;j++)
{
//遍历数组将消息发给其他客户端
if(usr_arr[j].cin.sin_port != cin.sin_port)
{
sendto(sfd,&cli,sizeof(cli),0,(struct sockaddr*)&(usr_arr[j].cin),sizeof(usr_arr[j].cin));
perror("sendto");
}
}
}
}
//写事件
if(pfds[1].revents == POLLIN )
{
memset(cli.msgText,0,sizeof(cli.msgText));
fgets(cli.msgText,sizeof(cli.msgText),stdin);
cli.msgText[strlen(cli.msgText)-1]=0;
cli.type = 3;
for(int c=0;c<i;c++)
{
sendto(sfd,&cli,sizeof(cli),0,(struct sockaddr*)&(usr_arr[c].cin),sizeof(usr_arr[c].cin));
perror("sento");
}
}
}
close(sfd);
return 0;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/wait.h>
#include <semaphore.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/times.h>
#include <sys/select.h>
#include <sqlite3.h>
int main(int argc, const char *argv[])
{
//创建套接字
int cfd = socket(AF_INET,SOCK_DGRAM,0);
if(cfd == -1)
{
perror("socket error");
return -1;
}
//printf("套接字创建成功! cfd = %d\n",cfd);
//端口号快速重用
int reuse = -1 ;
if(setsockopt(cfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))==-1)
{
perror("setsockopt error");
return -1;
}
//printf("端口快速重用成功!\n");
//绑定
/*struct sockaddr_in cin;
cin.sin_family = AF_INET;
cin.sin_port = htons(CLI_PORT);
cin.sin_addr.s_addr = inet_addr(CLI_IP);
if(bind(cfd,(struct sockaddr*)&cin,sizeof(cin)) == -1)
{
perror("bind error");
return -1;
}
printf("绑定成功!\n");*/
//数据收发
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(atoi(argv[2]));
sin.sin_addr.s_addr = inet_addr(argv[1]);
//创建一个用于检测文件描述符的容器
struct pollfd pfds[2];
pfds[0].fd = cfd; //表示第一个元素检测0号文件描述符
pfds[0].events = POLLIN; //要检测0号文件描述符的读事件
pfds[1].fd = 0; //表示第一个元素检测0号文件描述符
pfds[1].events = POLLIN; //要检测0号文件描述符的读事件
int res=-1;
struct usr usr_arr[1024]={0};
struct cli_msg cli;
struct cli_msg cli1;
char buf[128]="";
int i=0;
while(1)
{
//登陆后输入ID并存入信息结构体中
printf("\033[01;33;10m请输入ID:\033[0m");
scanf("%s",cli.usrname);
//printf("%s\n",cli.usrname);
cli.type = 1;
//向服务器发送ID和地址信息
sendto(cfd,&cli,sizeof(cli),0,(struct sockaddr*)&sin,sizeof(sin));
//服务器判断ID是否存在后返回结果
recvfrom(cfd,&buf,sizeof(buf),0,NULL,NULL);
if(strcmp(buf,"1")==0)
{
printf("\033[01;31;10m用户名重复!请重新输入!\033[0m\n");
}else
{
break;
}
}
while(1)
{
res = poll(pfds,2,-1); //阻塞检测文件描述符集合中是否有事件产生
if(res == 0)
{
printf("time out\n");
return -1;
}else if(res == -1)
{
perror("poll error");
return -1;
}
//读事件
if(pfds[0].revents == POLLIN)
{
recvfrom(cfd,&cli1,sizeof(cli1),0,NULL,NULL);
if(cli1.type ==2)
{
printf("\033[01;32;10m%s:\033[0m%s\n",cli1.usrname,cli1.msgText);
}else if(cli1.type == 3)
{
printf("\033[01;31;10m>>>>>>>>>>系统提示:%s<<<<<<<<<<\033[0m\n",cli1.msgText);
}
}
//写事件
if(pfds[1].revents == POLLIN )
{
//memset(cli.msgText,0,sizeof(cli.msgText));
fgets(cli.msgText,sizeof(cli.msgText),stdin);
cli.msgText[strlen(cli.msgText)-1]=0;
cli.type = 2;
sendto(cfd,(struct cli_msg*)&cli,sizeof(cli),0,(struct sockaddr*)&sin,sizeof(sin));
//printf("%s\n",cli.msgText);
}
}
close(cfd);
return 0;
}