实现了聊天功能,quit退出功能,文本保存功能
client_1.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <time.h>
#include <fcntl.h>
char name[100] = {}; // 记录客户端的名字
int sockfd;
void init_client()
{
// 初始化并连接到服务端
// 1、创建通信节点(通信设备)
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
perror("socket error");
exit(1);
}
// 2、向服务器发起连接
// 配置对方的通信地址
struct sockaddr_in addr;
addr.sin_family = AF_INET; // 协议族
addr.sin_port = htons(10086); // 端口号
addr.sin_addr.s_addr = inet_addr("172.100.0.210"); // 服务端的IP地址
// 3.连接服务端
int ret = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
if (ret == -1)
{
perror("connet error");
exit(1);
}
printf("客户端启动成功\n");
}
int connect_handle()
{
// 开一个线程用来接收服务端转发来的消息 recv_pthread
pthread_t tid;
void *client_read(void *);
pthread_create(&tid, NULL, client_read, NULL);
// 进入信息发给服务端,服务端进行转发和记录
// 可以自由的发送信息给服务端(群发信息) 消息格式 ==> 用户名:消息
char buf2[100] = {};;
sprintf(buf2,"欢迎%s进入聊天室\n", name);
write(sockfd,buf2, strlen(buf2));
// 发送数据
while (1)
{
char buf[100] = {};
printf(">>");
scanf("%s",buf);
char msg[200] = {};
sprintf(msg, "%s:%s", name, buf);
int send_size = write(sockfd, msg, strlen(msg));
if (0 == strcmp(buf, "quit"))
{
memset(buf2, 0, sizeof(buf2));
sprintf(buf2, "\n%s退出聊天室", name);
write(sockfd, buf2, strlen(buf2));
break;
}
}
close(sockfd);
}
void *client_read(void *arg)
{
// 接受数据
while (1)
{
char buf[100] = {};
int recv_size = read(sockfd, buf, sizeof(buf));
if (recv_size <= 0)
{
printf("已经与服务器断开链接\n");
sleep(1);
pthread_exit(NULL);
}
printf("%s\n", buf);
}
}
int main()
{
init_client();
// 输入用户名
printf("请输入您的昵称:");
scanf("%s", name);
// 输入一些提示:
printf("---------------------\n");
// 欢迎加入XXXX
printf("欢迎%s加入lgl粉丝后援会\n",name);
// 输入quit可以退出聊天室
printf("提示:输入quit可以退出\n");
printf("---------------------\n");
// 做信息处理
connect_handle();
return 0;
}
sever_1.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include <sys/select.h>
#include <sys/time.h>
#include <fcntl.h>
#include <sys/stat.h>
int clientfds[100]; // 记录客户端的连接套接字
// 注意:判断一下该套接字描述符是否非0
int size = 100; // 群聊中的最大人数限制
int sockfd;
int name[100] = {};
pthread_mutex_t mutex;
/**
* @brief 服务端初始化
*
* @param port 网络程序对应的端口号
*/
void init_server(int port)
{
// 1、创建通信节点(通信设备)
printf("创建socket对象...\n");
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
perror("socket error");
exit(1);
}
// 1.2设置套接字选项为允许立即重用地址
int optval = 1;
int r = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void *)&optval, sizeof(optval));
if (r == -1)
{
perror("setsockopt error");
exit(1);
}
// 2、绑定(准备通信地址)
printf("绑定socket对象与地址...\n");
struct sockaddr_in addr = {};
addr.sin_family = AF_INET; // 协议族
addr.sin_port = htons(port); // 端口号
addr.sin_addr.s_addr = inet_addr("172.100.0.210"); // 必须是本机的有效IP地址
// addr.sin_addr.s_addr = INADDR_ANY; // 使用本机任意地址(代表本机上所有有效地址)
int ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
if (ret == -1)
{
perror("bind error");
exit(1);
}
// 3、监听
printf("设置监听\n");
ret = listen(sockfd, 100);
if (ret == -1)
{
perror("listen error");
exit(1);
}
printf("等待客户端链接...\n");
}
void sendmsgtoall(char *msg)
{
int i = 0;
for (i = 0; i < size; i++)
{
if (clientfds[i] != 0)
{
printf("send to %d\n", clientfds[i]);
write(clientfds[i], msg, strlen(msg));
}
}
}
void jilu(char *buf)
{
int fd2 = open("1.txt", O_RDWR | O_CREAT);
lseek(fd2, 0, SEEK_END);
write(fd2, buf, strlen(buf));
write(fd2, "\n", strlen("\n"));
printf("read success");
}
// void *server_pthread(void *confd)
// {
// int fd = *(int *)confd;
// while (1)
// {
// char buf[200] = {};
// char ts[100] = {};
// char name[100] = {};
// // 接受客户端的数据
// //memset(buf, 0, sizeof(buf));
// int ret = read(fd, buf, sizeof(buf));
// if(ret ==-1)
// {
// perror("rad error");
// exit(1);
// }
// char b[100]={};
// strcpy(b,&buf[0]);
// // 先判断客户端的数据是否为一些请求:
// if (strcmp(b, "quit")== 0||ret<=0) // 如果是quit服务端来做处理
// {
// printf(".......%d......",strcmp(b, "quit"));
// sprintf(ts, "欢送 %s 离开群聊\n", name); // 转发一条 XXX退出群聊 的消息给所有人
// int index=0;
// for (index = 0; index < size; index++)
// {
// if (clientfds[index] == fd)
// {
// clientfds[index] = 0;
// break;
// }
// }
// // 记录退群信息
// printf("fd = %dquit\n",fd);
// pthread_exit(NULL);
// sendmsgtoall(buf);
// break;
// }
// else
// {
// // 如果是正常发送消息,则把消息进行转发
// for (int i = 0; i < size; i++)
// {
// // 若值为0,则没有此群友,表示已经退出或未被占有
// if (clientfds[i] != 0)
// {
// printf("%s", buf);
// }
// }
// // 通过clientfds中保存好的连接套接字进行消息转发
// // 把消息记录到一个文本文件中作为聊天记录
// // memset(sockfd,0,sizeof(sockfd));
// }
// sendmsgtoall(buf);
// }
// }
void *server_pthread(void *arg)
{
int fd = *(int *)arg;
printf("pthread = %d\n", fd);
while (1)
{
char buf[100] = {};
int ret = read(fd, buf, sizeof(buf));
if (ret <= 0)
{
int i;
for (i = 0; i < size; i++)
{
if (fd == clientfds[i])
{
clientfds[i] = 0;
break;
}
}
printf("退出:fd = %dquit\n", fd);
pthread_exit(NULL);
}
// 把服务器接受到的信息发给所有的客户端
sendmsgtoall(buf);
jilu(buf);
}
}
// void *jilu(void *arg)
// {
// int fd1 = *(int *)arg;
// while(1)
// {
// char buf1[100] = {};
// int fd2 = open("1.txt", O_RDWR | O_CREAT);
// pthread_mutex_lock(&mutex);
// int ret = read(fd1, buf1, sizeof(buf1));
// pthread_mutex_unlock(&mutex);
// if (ret > 0)
// {
// int r = write(fd2, buf1, sizeof(buf1));
// if(r==-1)
// perror("write error");
// lseek(fd2, 0, SEEK_END);
// printf("read success");
// }
// }
// }
void server()
{
while (1)
{
// 接收连接
struct sockaddr_in client_addr; // 保存客户端的地址信息
socklen_t len = sizeof(client_addr);
int fd = accept(sockfd, (struct sockaddr *)&client_addr, &len);
if (fd == -1)
{
printf("客户端连接出错。。。\n");
continue;
}
int i = 0;
for (i = 0; i < size; i++)
{
if (clientfds[i] == 0)
{
clientfds[i] = fd;
// 成功加入群聊
printf("fd=%d\n", fd);
// 成功加入群聊则开一个线程去对该客户端进行数据处理
pthread_t tid;
pthread_create(&tid, 0, server_pthread, &fd);
pthread_detach(tid);
// pthread_t pid;
// pthread_create(&pid,0,jilu,&fd);
// pthread_detach(pid);
break;
}
if (size == i) // 群聊满了
{
char *str = "对不起,聊天室已满";
// 回复客户端一条信息,群聊已经满了
write(fd, str, strlen(str));
// 并断开对该客户端的连接
close(fd);
}
}
}
}
int main()
{
// 初始化服务端
init_server(10086);
// 等待客户端的连接,并对连接好的客户端做信息处理 并发型服务端
server();
}