网络聊天室:
程序代码:
ser.c
#include <myhead.h>
//定义消息类型结构体
struct xiaoxi {
char type;
char name[20];
char text[100];
};
int main(int argc, const char* argv[])
{
// 创建套接字
int sfd = socket(AF_INET, SOCK_STREAM, 0);
if (sfd == -1)
{
perror("socket error");
return -1;
}
// 设置端口快速重用
int reuse = 1;
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
{
perror("setsockopt error");
return -1;
}
// 绑定
// 定义地址信息结构体
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]);
if (bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) == -1)
{
perror("bind error\n");
return -1;
}
// 设置监听
if ((listen(sfd, 128)) == -1)
{
perror("listen error\n");
return -1;
}
// 4接受请求
// 存储客户端信息结构体
struct sockaddr_in cin;
cin.sin_family = AF_INET;
cin.sin_port = htons(atoi(argv[2]));
cin.sin_addr.s_addr = inet_addr(argv[1]);
socklen_t socklen = sizeof(cin);
struct sockaddr_in arr_cin[1024];
// 定义
struct pollfd fds[1024];
for (int i = 0; i < 1024; i++)
{
fds[i].fd = -1;
fds[i].events = POLLIN;
}
//将0和sfd放入数组
fds[0].fd = 0;
fds[1].fd = sfd;
struct xiaoxi rec;//消息类型结构体变量
char buf[128] = "";//接受消息的容器
int newfd = -1; //存储文件描述符
while (1)
{
int res = poll(fds, 1024, -1);
if (res < 0)
{
perror("poll error");
return -1;
}
else if (res == 0)
{
printf("time out\n");
return -1;
}
if (fds[0].revents == POLLIN) //终端标准输入描述符
{
bzero(buf, sizeof(buf));
fgets(buf, sizeof(buf), stdin);
buf[strlen(buf) - 1] = 0;
for (int j = 4; j < 1024; j++)
{
send(fds[j].fd, buf, sizeof(buf), 0);
}
}
if (fds[1].revents == POLLIN)//sfd
{
if ((newfd = accept(sfd, (struct sockaddr*)&cin, &socklen)) == -1)
{
perror("accept error\n");
}
arr_cin[newfd] = cin; //将地址信息存入cin
printf("------[%s:%d]连接成功------\n", inet_ntoa(arr_cin[newfd].sin_addr), htons(arr_cin[newfd].sin_port));
fds[newfd].fd = newfd; //新生成的文件描述符放入数组
fds[newfd].events = POLLIN;
}
for (int i = 4; i < 1024; i++)
{
if (fds[i].fd < 0)
{
continue;
}
if (fds[i].revents == POLLIN)
{
bzero(buf, sizeof(buf));
bzero(buf, sizeof(buf));
int res = recv(fds[i].fd, &rec, sizeof(rec), 0); //接收客户端消息
if (res == 0)
{
close(fds[i].fd);
printf("------[%s:%d]断开连接------\n", inet_ntoa(arr_cin[fds[i].fd].sin_addr), htons(arr_cin[fds[i].fd].sin_port));
fds[i].fd = -1;
arr_cin[fds[i].fd].sin_addr.s_addr = 0;
arr_cin[fds[i].fd].sin_port = 0;
continue;
}
// 判断消息类型
if (rec.type == 'L') // 登录消息
{
for (int j = 4; j < 1024; j++)//发送给每个客户端
{
if (j == i)
{
continue;
}
bzero(buf, sizeof(buf));
sprintf(buf, "----------%s上线-----------", rec.name);
send(fds[j].fd, buf, strlen(buf), 0);
}
}
else if (rec.type == 'C') // 聊天消息
{
for (int j = 4; j < 1024; j++)
{
if (j == i)
{
continue;
}
bzero(buf, sizeof(buf));
sprintf(buf, "%s:%s", rec.name, rec.text);
send(fds[j].fd, buf, strlen(buf), 0);
}
}
else
{ //退出消息
//(rec.type == 'Q')
for (int j = 4; j < 1024; j++)
{
if (j == i)
{
continue;
}
bzero(buf, sizeof(buf));
sprintf(buf, "-----------%s下线------------", rec.name);
send(fds[j].fd, buf, strlen(buf), 0);
}
}
}
}
}
return 0;
}
cli.c
#include <myhead.h>
struct xiaoxi {
char type;
char name[20];
char text[100];
};
int main(int argc, const char* argv[])
{
// 创建套接字
int cfd = socket(AF_INET, SOCK_STREAM, 0);
if (cfd == -1)
{
perror("socket error\n");
return -1;
}
// 端口快速重用
int reus = 1;
if ((reus = setsockopt(cfd, SOL_SOCKET, SO_REUSEADDR, &reus, sizeof(reus))) == -1)
{
perror("setsockopt error\n");
return -1;
}
// 定义地址信息结构体
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]);
// 向客户端发送连接请求
if (connect(cfd, (struct sockaddr*)&sin, sizeof(sin)) == -1)
{
perror("connect error");
return -1;
}
struct xiaoxi sendi;
char buf[100] = "";
char nbuf[20] = "";
struct pollfd fds[2];
fds[0].fd=0;
fds[0].events = POLLIN;
fds[1].fd=cfd;
fds[1].events = POLLIN;
printf("请输入用户名:");
fgets(nbuf,sizeof(nbuf),stdin);
nbuf[strlen(nbuf)-1]=0;
sendi.type = 'L';
strcpy(sendi.name, nbuf);
send(cfd, &sendi, sizeof(sendi), 0);
while (1)
{
int res = poll(fds,2,-1); //阻塞检测
if (fds[0].revents == POLLIN)
{
bzero(buf, sizeof(buf));
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1]=0;
sendi.type = 'C';
if(strcmp(buf,"quit")==0)
{
sendi.type = 'Q';
sendto(cfd, &sendi, sizeof(sendi), 0, (struct sockaddr*)&sin, sizeof(sin));
break;
}
strcpy(sendi.text,buf);
sendto(cfd, &sendi, sizeof(sendi), 0, (struct sockaddr*)&sin, sizeof(sin));
}
if (fds[1].revents == POLLIN)
{
bzero(buf, sizeof(buf));
int res = recv(cfd, buf, sizeof(buf), 0);
printf("%s\n", buf);
if (res == 0)
{
printf("服务器下线\n");
break;
}
}
}
close(cfd);
return 0;
}
运行结果: