c语言开发 练手项目,C语言练手项目--C 语言编写聊天室

本文介绍了一个使用C语言实现的TCP聊天室项目,涵盖了TCP/IP协议的C/S模型、epoll机制、非阻塞socket以及文件操作。项目采用epoll的ET模式以提高并发效率,支持多个用户接入并进行实时聊天。通过fork创建进程,利用管道进行父子进程间通信,实现了聊天信息的传递。
摘要由CSDN通过智能技术生成

C 语言编写聊天室一、需求二、知识点1、TCP/IP协议(1)C/S模型(2)常规步骤(3)阻塞与非阻塞 socket(4)epoll2、文件操作3、数据库三、实现1、思路2、代码(1)utility.h(2)server.c(3)client.c3、运行结果参考

一、需求

基于TCP编写,一个聊天室C/S。

基本要求

支持多个用户接入,实现聊天室的基本功能

使用epoll机制实现并发、增加效率

使用fork创建两个进程

将聊天信息写到管道(pipe),并发送给父进程

使用epoll机制接受服务端发来的信息,并显示给用户,使用户看到其他用户的聊天信息

暂且不含线程池、多线程编程、超时重传、确认收包等

后续待加功能

实现简单的文件传输。

用户注册和登陆

二、知识点

1、TCP/IP协议

(1)C/S模型

5ee0c5a150388cb2daf2a8992966a324.png

(2)常规步骤

TCP服务端

1、使用 socket()创建 TCP 套接字(socket)

2、将创建的套接字绑定到一个本地地址和端口上(Bind)

3、将套接字设为监听模式,准备接收客户端请求(listen)

4、等待客户请求到来: 当请求到来后,接受连接请求,返回一个对应于此次连接的新的套接字(accept)

5、用 accept 返回的套接字和客户端进行通信(使用write()/send()或send()/recv() )

6、返回,等待另一个客户请求

7、关闭套接字

//server.cpp代码(通信模块):

//服务端地址 ip地址 + 端口号

struct sockaddr_in serverAddr;

serverAddr.sin_family = PF_INET;

serverAddr.sin_port = htons(SERVER_PORT);

serverAddr.sin_addr.s_addr = inet_addr(SERVER_HOST);

//服务端创建监听socket

int listener = socket(PF_INET, SOCK_STREAM, 0);

if(listener < 0) { perror("listener"); exit(-1);}

printf("listen socket created \n");

//将服务端地址与监听socket绑定

if( bind(listener, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) {

perror("bind error");

exit(-1);

}

//开始监听

int ret = listen(listener, 5);

if(ret < 0) { perror("listen error"); exit(-1);}

printf("Start to listen: %s\n", SERVER_HOST);

TCP客户端

1、创建套接字(socket)

2、使用 connect() 建立到达服务器的连接(connect)

3、客户端进行通信(使用 write()/send() 或 send()/recv() )

4、使用 close() 关闭客户连接

//client.cpp代码(通信模块):

//客户要连接的服务端地址( ip地址 + 端口号)

struct sockaddr_in serverAddr;

serverAddr.sin_family = PF_INET;

serverAddr.sin_port = htons(SERVER_PORT);

serverAddr.sin_addr.s_addr = inet_addr(SERVER_IP);

// 创建套接字(socket)

int sock = socket(PF_INET, SOCK_STREAM, 0);

if(sock < 0) { perror("sock error"); exit(-1); }

//向服务器发出连接请求(connect)

if(connect(sock, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) {

perror("connect error");

exit(-1);

}

(3)阻塞与非阻塞 socket

分类阻塞非阻塞

概念对一个文件描述符指定的文件或设备, 一般有两种工作方式: 阻塞与非阻塞方式

当试图对该文件描述符进行读写时,如果当时没有数据可读,或者暂时不可写,程序就进入等待状态,直到有东西可读或者可写为止如果没有数据可读,或者不可写,读写函数马上返回,而不会等待

举例比如说小明去找一个女神聊天,女神却不在

如果小明舍不得走,只能在女神大门口死等着,当然小明可以休息。当女神来了,她会把你唤醒(囧,因为挡着她门了),这就是阻塞方式如果小明舍不得走,只能在女神大门口死等着,当然小明可以休息。当女神来了,她会把你唤醒(囧,因为挡着她门了),这就是阻塞方式

区别等待立即返回

本项目采用更高效的做法,所以应该将socket设置为非阻塞方式。这样能充分利用服务器资源,效率得到了很大提高本项目采用更高效的做法,所以应该将socket设置为非阻塞方式。这样能充分利用服务器资源,效率得到了很大提高

//utility.h代码(设置非阻塞函数模块):

//将文件描述符设置为非阻塞方式(利用fcntl函数)

int setnonblocking(int sockfd)

{

fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)| O_NONBLOCK);

return 0;

}

(4)epoll

当服务端的在线人数越来越多,会导致系统资源吃紧,I/O 效率越来越慢,这时候就应该考虑 epoll 了。epoll 是 Linux 内核为处理大批句柄而作改进的 poll ,是 Linux 特有的 I/O 函数。

其特点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值