在线聊天:
服务器端:
#include<myhead.h>
typedef struct mess{
char flag;
char name[20];
char message[128];
}mess;
typedef struct fds
{
char name[20];
struct sockaddr_in cin;
}fds_t;
int main(int argc, char const *argv[])
{
char const *IP=argv[1];
char const *PORT=argv[2];
int P=atoi(PORT);
int sfd=socket(AF_INET,SOCK_STREAM,0);//创建套接字
if(sfd==-1)
{
perror("scoket:");
return -1;
}
struct sockaddr_in sin;//填充结构体信息,本机IP和端口号。用于服务器端绑定
sin.sin_addr.s_addr=inet_addr(IP);
sin.sin_family=AF_INET;
sin.sin_port=htons(P);
if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))==-1)//绑定结构体信息
{
perror("bind:");
return -1;
}
int reuse = 1;
if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))==-1)
{
perror("setsockopt error");
return -1;
}
if(listen(sfd,128)==-1)//启动监听
{
perror("listen:");
return -1;
}
char buf[128]="";
fd_set temps,reads;
int max=sfd;
int newsfd;
fds_t fds[1024];
struct sockaddr_in temp;
int len=sizeof(temp);
FD_ZERO(&temps);
FD_ZERO(&temps);
FD_SET(0,&temps);
FD_SET(sfd,&temps);
while (1)
{
reads=temps;
int re=select(max+1,&reads,NULL,NULL,NULL);//阻塞等待标识符发生对应的事件,当事件发生时只保留对应的标识符
if(re==-1)
{
perror("select:");
return -1;
}
for(int k=0;k<=max;k++)//循环判断对应哪个标识符存在,再让存在的标识符找对应的事件。
{
if(FD_ISSET(k,&reads))
{
if(k==0)
{
scanf("%s",buf);
mess t;
strcpy(t.message,buf);
t.flag=2;
for(int i=4;i<=max;i++)
{
write(i,&t,sizeof(t));
}
}
else if(k==sfd)
{
newsfd=accept(sfd,(struct sockaddr*)&temp,&len);
if(newsfd==-1)
{
perror("accept:");
return -1;
}
char n[20];
bzero(n,20);
read(newsfd,n,20);
printf("[%s:%d]%s登录成功\n",inet_ntoa(temp.sin_addr),ntohs(temp.sin_port),n);
FD_SET(newsfd,&temps);
fds[newsfd].cin=temp;
mess l;
l.flag=1;
strcpy(l.name,n);
strcpy(fds[newsfd].name,n);
max=max>newsfd?max:newsfd;
for(int i=4;i<=max;i++)
{
if(i!=newsfd)
{
write(i,&l,sizeof(l));
}
}
}
else
{
mess m3;
bzero(&m3,sizeof(m3));
read(k,&m3,sizeof(m3));
if(m3.flag==4)
{
printf("[%s:%d]%s退出登录\n",inet_ntoa(fds[k].cin.sin_addr),ntohs(fds[k].cin.sin_port),m3.name);
close(k);
FD_CLR(k,&temps);
for(int l=max;l>=sfd;l--)
{
if(FD_ISSET(l,&temps))
{
max=l;
break;
}
}
for(int i=4;i<=max;i++)
{
write(i,&m3,sizeof(m3));
}
continue;
}
else if(m3.flag==1 | m3.flag==2 | m3.flag==3)
{
for(int i=4;i<=max;i++)
{
if(i!=k)
{
write(i,&m3,sizeof(m3));
}
}
}
}
}
}
}
return 0;
}
客户端:
#include <myhead.h>
int sfd;
typedef struct mess
{
char flag;
char name[20];
char message[128];
} mess;
void *p(void *a) // 读服务器发来的消息
{
mess m;
int len = sizeof(m);
while (1)
{
bzero(&m, len);
int a = read(sfd, &m, len);
if (a == 0)
{
printf("服务器已断开........\n");
exit(0);
}
if (m.flag == 1) // 接收用户加入群聊的消息
{
printf("\033[4D系统消息:%s已加入群聊\n", m.name);
}
else if (m.flag == 2) // 接收系统消息
{
printf("\033[4D系统消息:%s\n", m.message);
}
else if (m.flag == 3) // 接收群聊中用户发送的消息
{
printf("\033[4D%s:%s\n", m.name, m.message);
}
else // 接收用户退出群聊的消息
{
printf("\033[4D%s退出群聊\n", m.name);
}
printf("你:");
fflush(stdout);
}
}
int main(int argc, char const *argv[])
{
const char *IP = argv[1];
int P = atoi(argv[2]);
sfd = socket(AF_INET, SOCK_STREAM, 0); // 创建TCP客户端
if (sfd == -1)
{
perror("socket:");
return -1;
}
struct sockaddr_in t; // 填充服务器端的iP和端口号,用于连接服务器端
t.sin_addr.s_addr = inet_addr(IP);
t.sin_family = AF_INET;
t.sin_port = htons(P);
char name2[20];
printf("请输入姓名:");
scanf("%s", name2);
if (connect(sfd, (struct sockaddr *)&t, sizeof(t)) == -1) // 连接到服务器端
{
perror("connet:");
return -1;
}
write(sfd, name2, strlen(name2));
printf("登录成功\n");
pthread_t id;
if (pthread_create(&id, 0, p, NULL) != 0)
{
perror("create:");
return -1;
};
mess m2;
while (1)
{
bzero(&m2, sizeof(m2));
m2.flag = 3;
printf("你:");
scanf("%s", m2.message);
strcpy(m2.name, name2);
if (strcmp(m2.message, "quit") == 0)
{
m2.flag = 4;
write(sfd, &m2, sizeof(m2));
printf("退出成功!\n");
exit(0);
}
write(sfd, &m2, sizeof(m2));
}
close(sfd);
return 0;
}