C语言多人聊天室 ---chat(客户端聊天)

news/2025/2/24 17:17:28

head.h

#ifndef __HEAD_H
#define __HEAD_H

// 常用头文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 网络编程涉及的头文件
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>

#include <sys/types.h>

// 本机字节序和网络字节序转换相关函数的头文件
#include <arpa/inet.h>

// 关闭套接字用close函数需要的头文件
#include <unistd.h>

//线程相关的函数头, mutex相关的函数
#include <pthread.h>

// 类型重命名:地址结构体的规范
typedef struct sockaddr SockAddr;

// 地址结构体的规范的实现结构体
typedef struct sockaddr_in SockAddrIn;


// if_nametoindex
#include <net/if.h>

#include <sys/select.h>
#include <sys/time.h>

// JSON字符串的封装
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 文件操作需要的头文件
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <fcntl.h>
#include <mysql/mysql.h>

// selet
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>

// 定义外部变量
//int sockfdNUM[10] = {0};

#endif

p_char.h

#ifndef _P_CHAT_H
#define _P_CHAT_H

#define BUF_SIZE 1024

#include "head.h"

// 错误处理函数,用于输出错误信息并终止程序
void error_handling(const char *message);

#endif

p_chat.c

#include "p_chat.h"

// 私聊接收任务函数
void *s_private_chat(void *arg)
{
    // 1.获取客户端套接字
    int sock = *(int *)arg;

    char buf[1024] = {0};
    while (1)
    {
        scanf("%s", buf);
        send(sock, buf, strlen(buf), 0);
        if (strcmp(buf, "quit") == 0)
        {
            break;
        }
        memset(buf, 0, sizeof(buf));
    }

    // 关闭服务端套接字
    close(sock);
    exit(0); // 结束整个线程
}

void *r_private_chat(void *arg)
{
    // 1.获取客户端套接字
    int sock = *(int *)arg;

    char buf[1024] = {0};
    while (1)
    {
        recv(sock, buf, sizeof(buf), 0);
        printf("%s\n", buf);
        memset(buf, 0, sizeof(buf));
    }

    // 关闭服务端套接字
    close(sock);
}

// 客户端
int main(int argc, char const *argv[])
{
    // 创建线程id
    pthread_t tid1;
    pthread_t tid2;

    // 1.创建socket
    int s_sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == s_sockfd)
    {
        perror("socket failed");
        return -1;
    }

    // 2.绑定地址
    SockAddrIn serverAddr;
    // ipv4协议
    serverAddr.sin_family = AF_INET;
    // 端口
    serverAddr.sin_port = htons(8888);
    // ip地址
    serverAddr.sin_addr.s_addr = inet_addr("192.168.118.129");

    // 创建一个用于存放的json字符的数组
    char *jsonString;

    // 3.连接服务器
    int ret = connect(s_sockfd, (SockAddr *)&serverAddr, sizeof(serverAddr));
    if (-1 == ret)
    {
        perror("connect failed");
        return -1;
    }

    // 4.1 接收服务器消息
    char buf[2048] = {0};
    ret = recv(s_sockfd, buf, sizeof(buf), 0);
    if (-1 == ret)
    {
        perror("recv failed");
        return -1;
    }

    int uid, fid;
    uid = atoi(argv[1]);
    fid = atoi(argv[2]);
    printf("uid = %d\n", uid);
    printf("fid = %d\n", fid);
    printf("s_sockfd = %d\n", s_sockfd);

    // 判断上一个进程传来的数据
    if (strcmp(argv[3], "私聊") == 0)
    {
        // 向服务端发送自己的状态
        int stat = 1;
        send(s_sockfd, &stat, sizeof(stat), 0);
        // 私聊
        // 发送uid
        send(s_sockfd, &uid, sizeof(uid), 0);
        // 发送fid
        send(s_sockfd, &fid, sizeof(fid), 0);
        //puts("待接收历史消息");

        // 清空buf
        memset(buf, 0, sizeof(buf));
        // 接收聊天记录
        recv(s_sockfd, buf, sizeof(buf), 0);
        //puts("历史消息接收完毕:");
        puts(buf);
        puts("以上是历史消息");
        // 创建线程
        pthread_create(&tid1, NULL, s_private_chat, &s_sockfd);
        pthread_create(&tid2, NULL, r_private_chat, &s_sockfd);
        // 等待线程结束
        pthread_join(tid1, NULL);
    }
    else if (strcmp(argv[3], "群聊") == 0)
    {
        // 向服务端发送自己的状态
        int stat = 2;
        send(s_sockfd, &stat, sizeof(stat), 0);
        // 公屏聊天
        // 发送uid
        send(s_sockfd, &uid, sizeof(uid), 0);
        
        puts("开始聊天");

        // 创建线程
        pthread_create(&tid1, NULL, s_private_chat, &s_sockfd);
        pthread_create(&tid2, NULL, r_private_chat, &s_sockfd);
        // 等待线程结束
        pthread_join(tid1, NULL);
    }

    // 5.关闭socket
    close(s_sockfd);
    puts("关闭socket");
    return 0;
}

makefile

SRCS = $(wildcard *.c)
OBJS = $(patsubst *.c,*.o,$(SRCS))
CC = gcc
TARGET = p_chat
LDFLAGS = -lpthread -lmysqlclient

.PHONY : clean

$(TARGET) : $(OBJS)
	$(CC)  $^ -o $@ $(LDFLAGS)
	
clean :
	rm *.o

run :
	./$(TARGET)

show :
	echo $(SRCS) / $(OBJS)


http://www.niftyadmin.cn/n/5864638.html

相关文章

给小米/红米手机root(工具基本为官方工具)——KernelSU篇

目录 前言准备工作下载刷机包xiaomirom下载刷机包【适用于MIUI和hyperOS】“hyper更新”微信小程序【只适用于hyperOS】 下载KernelSU刷机所需程序和驱动文件 开始刷机设置手机第一种刷机方式【KMI】推荐提取boot或init_boot分区 第二种刷机方式【GKI】不推荐 结语 前言 刷机需…

【HeadFirst系列之HeadFirst设计模式】第10天之迭代器与组合模式:遍历与管理的艺术

迭代器与组合模式&#xff1a;遍历与管理的艺术 在《Head First 设计模式》中&#xff0c;**迭代器模式&#xff08;Iterator Pattern&#xff09;和组合模式&#xff08;Composite Pattern&#xff09;**是两个非常重要的设计模式。迭代器模式帮助我们遍历集合中的元素&#…

pikachu靶场搭建教程

需要的东西 phpStudy&#xff1a; 链接&#xff1a; https://pan.baidu.com/s/1fJ-5TNtdDZGUf5FhTm245g 提取码&#xff1a;0278 pikachu-master&#xff1a; Github链接&#xff1a;https://github.com/zhuifengshaonianhanlu/pikachu 链接&#xff1a; https://pan.baidu.c…

Java实现斗地主-做牌以及对牌排序

卡牌类 public class Card {private String size;//大小private String color;//花色private int value;//权值public Card() {}public Card(String size, String color, int value) {this.size size;this.color color;this.value value;}public String toString(){return …

vue2 和 vue3 中 computer 计算属性的用法

Vue 2 中的 computed 在 Vue 2 中&#xff0c;计算属性是响应式的&#xff0c;并且基于 getter 进行缓存&#xff0c;只有依赖的响应式数据发生变化时才会重新计算。 基本用法 <template><div><p>原始消息&#xff1a;{{ message }}</p><p>反…

22.回溯算法4

递增子序列 这里不能排序&#xff0c;因为数组的顺序是对结果有影响的&#xff0c;所以只能通过used数组来去重 class Solution { public:vector<int> path;vector<vector<int>> res;void backtracking(vector<int>& nums,int start){if(path.si…

“国补”带火手机换新,出售旧手机应如何保护个人信息安全

在“国补”政策的推动下,手机换新热潮正席卷而来。“国补”以其诱人的补贴力度,成功激发了消费者更换手机的热情。无论是渴望体验最新技术的科技爱好者,还是对旧手机性能不满的普通用户,都纷纷投身到这场手机换新的浪潮之中。 随着大量消费者参与手机换新,二手手机市场迎来…

机器学习数学通关指南——拉格朗日乘子法

前言 本文隶属于专栏《机器学习数学通关指南》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和参考文献请见《机器学习数学通关指南》 正文 一句话总结 拉格朗日乘子法…