网络编程基于TCP/IP实现简单聊天室

实现了聊天功能,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();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值