C++ 文件传输和多人聊天室

两个主要的功能:

1.文件传输

2.多人聊天室

要用的技术点:epoll模型

出现的bug总结:

解决1个bug:每次客户端挂掉以后,就会报9:Bad file descriptormain.

解决办法:在if (len < 0)条件里面加入break就可以了

bug2:每次只能传回一次数据,数据同步的问题?

解决办法:把readLine函数写成readAll,问题解决,但是没找到原因是什么???

bug3:只能有一个人登录聊天室

解决了只能一人登录的问题,现在可以多人登录,但是消息还不是共享的

解决了,通过引入cli_map<int,Client>,去掉消息中的while(true)循环解决掉了。

bug4:无法在dubug文件夹中双击QQ_client_server.exe运行,通过http://t.csdnimg.cn/b1yiN博客看明白了

这时确定了要用缓冲区开头写一个字符C或者字符F的形式确定是文本输入还是文件输入

bug5:如何进行修改,可以区分开文本输入还是文件输入?

思路:要在QT客户端进行修改了,加了一个name_flag标志位

在修改了标志位name_flag以后,只有第一次输入名字的时候,前面有C,后面没有\n,后面就都有了

所以第一次需要提醒一下(在文本框中写上,请输出姓名)

bug6:将writeText函数抽象化的时候,遇到几个问题

1.访问Client的成员变量

传入了map<int,Client>指针,如果要访问Client的成员变量的时候,要这样操作:

(*client_map)[fd].name,

2.遍历map<int,Client>结构体数组:

还有想要遍历map<int,Client>结构体数组的时候,使用迭代器:for(auto it = (*client_map).begin(); it != (*client_map).end(); ++it),这里it的成员变量类型为:map<int,Client>::iterate

3.写入数据的时候使用了write(it->first, buffer, sizeof(buffer));

这里的sizeof(buffer) = 8,是一个指针的大小,所以,要把变量替换为原先的1024

bug7:传输文件功能实现:

需要记录文件名,文件大小等文件的基本信息,于是有两种思路:

思路1:在客户端将文件头信息和文件内容信息分开发送

思路2:在服务端对收到的buffer进行文件解析。对于小文件来说,需要用&&&&作为分隔符,接收到的buffer进行分割的代码是:

c++ 复制代码
char file_name[512] = "";
char file_size[64];
const char *d = "&&&&";
char *p;
//文件格式:F&&&&文件名&&&&文件大小&&&&文件内容
//第一次:F 不管
p = strtok(buffer,d);
//第二次 文件名
strcpy(file_name,strtok(NULL,d));
printf("second time:%s:%s\n",__FUNCTION__,file_name);
FILE *fp = fopen(file_name,"w");
if(fp == NULL){
    printf("无法写文件%s\n",file_name);
    exit(1);
}
//第三次 文件大小
strcpy(file_size,strtok(NULL,d));
int len = atoi(file_size);
printf("third time:%s:%d\n",__FUNCTION__,len);
//第四次 文件内容
strcpy(buffer,strtok(NULL,d));//buffer没有问题
printf("forth time:%s:%s\n",__FUNCTION__,buffer);

常用的一些转换方法

string a转换为char b[]的方法:strcpy(b,a);

QString转换为各种格式的数据的方法(要注意)

用printf("%s")打印string的方法:

string a;

printf("%s",a.c_str());

否则就会打印乱码

完整的代码:

QT客户端:

.pro文件中,要加

QT       += core gui sql network widgets

mainwindows.cpp文件

c++ 复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"



//用来on_btnSend_clicked发送消息的时的标志位,保证发送姓名的时候不带有\n,同时保证开启连接时发送的消息开头带有C
int name_flag = 0;

//用来传输文件名
int fileName_flag = 0;

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //设置状态栏格式
    statusBar()->setMinimumHeight(25);
    statusBar()->setStyleSheet(QString("QStatusBar::item{border: 1px}")); // 不显示边框

//    m_loadSize = 4*1024; // 每次发送的文件数据大小
//    m_totalBytes = 0;
//    m_bytesWritten = 0;
//    m_bytesToWrite = 0;

    m_tcpTextClient = new QTcpSocket(this); //创建socket变量
    m_tcpFileClient = new QTcpSocket(this);

    m_labSocketState = new QLabel("Socket状态:");//状态栏标签
    m_labSocketState->setMinimumWidth(250);
    statusBar()->addWidget(m_labSocketState);

    QString localIP = getLocalIP();//本机IP
    this->setWindowTitle(this->windowTitle()+"----本机IP:"+localIP);
    ui->comboServer->addItem(localIP);//在下拉框里面可以看到追加的ip,即localIP



    //显示连接状态
    connect(m_tcpTextClient,SIGNAL(connected()),this,SLOT(onConnected()));
    connect(m_tcpTextClient,SIGNAL(disconnected()),this,SLOT(onDisconnected()));
    //状态改变时要更新
    connect(m_tcpTextClient,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
    //读取从客户端传回的数据,
    connect(m_tcpTextClient,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));

}

MainWindow::~MainWindow()
{
    delete ui;
}

//获得本地ip
QString MainWindow::getLocalIP()
{
    //获取本机IPv4地址
    QString hostName = QHostInfo::localHostName();//本机主机名
    QHostInfo hostInfo = QHostInfo::fromName(hostName);
    QString localIP="";
    QList<QHostAddress> addList = hostInfo.addresses();
    if(!addList.isEmpty())
    {
        for(int i = 0;i<addList.count();i++)
        {
            QHostAddress aHost = addList.at(i);
            if(QAbstractSocket::IPv4Protocol==aHost.protocol())
            {
                localIP = aHost.toString();
                break;
            }
        }
    }
   return localIP;
}

//-------------------------------------------------------------------------
//这里是客户端的连接部分

void MainWindow::on_connectBt_clicked()
{//连接到服务器动作
    QString addr = ui->comboServer->currentText();
    quint16 port = ui->spinPort->value();
    m_tcpTextClient->connectToHost(addr, port);

//    m_bytesWritten = 0; // 初始化已发送字节为0
//    m_tcpFileClient->connectToHost(addr, port);

}


void MainWindow::on_disconnectBt_clicked()
{//断开与服务器的连接动作
    if (m_tcpTextClient->state()==QAbstractSocket::ConnectedState)
        m_tcpTextClient->disconnectFromHost();
    name_flag = 0;
}

void MainWindow::on_btnSend_clicked()
{//发送数据
    QString  msg=ui->editMsg->toPlainText();
    m_tcpTextClient->write("C");
//    qDebug() << msg;

    if (msg.isEmpty())
    {
        QMessageBox::information(this, "提示", "发送的消息不能为空!");
        return;
    }

    ui->plainTextEdit->appendPlainText("[out] "+msg);
    ui->editMsg->clear();
    ui->editMsg->setFocus();

    QByteArray  str=msg.toUtf8();
    if(name_flag != 0){
        str.append('\n');
    }
//    m_tcpTextClient->write(str.constData(),1024);
    name_flag = 1;
    qint64 flag = m_tcpTextClient->write(str);
    if(flag > 0){
        qDebug() << "success write,flag = " << flag;
    }else{
        qDebug() << "write error occurred";
    }

}

//显示连接的状态
void MainWindow::onConnected()
{ //connected()信号槽函数
    ui->plainTextEdit->appendPlainText("**已连接到服务器");
    ui->plainTextEdit->appendPlainText("**peer address:"+
                                   m_tcpTextClient->peerAddress().toString());
    ui->plainTextEdit->appendPlainText("**peer port:"+
                                   QString::number(m_tcpTextClient->peerPort()));
    ui->connectBt->setEnabled(false);
    ui->disconnectBt->setEnabled(true);
}

//显示断开连接的状态
void MainWindow::onDisconnected()
{//disConnected()信号槽函数
    ui->plainTextEdit->appendPlainText("**已断开与服务器的连接");
    ui->connectBt->setEnabled(true);
    ui->disconnectBt->setEnabled(false);
}


//文本读服务器的消息
void MainWindow::onSocketReadyRead()
{   //readyRead()信号槽函数
    while(m_tcpTextClient->canReadLine()){
        ui->plainTextEdit->appendPlainText("[in] "+ QString::fromUtf8(m_tcpTextClient->readAll()));
//        printf("readLine()buffer:%d\n",sizeof(m_tcpTextClient->readLine(1024)));
    }
}



//清空文本框消息
void MainWindow::on_clearBtn_clicked()
{
    ui->plainTextEdit->clear();
}

//发送文件
void MainWindow::on_btnSendFile_clicked()
{
    //为了和发送消息进行区分
    qint64 flag = m_tcpTextClient->write("F");
    if(flag > 0){
        qDebug() << "success write,flag = " << flag;
    }else{
        qDebug() << "write error occurred";
    }
    startTransfer();
}

void MainWindow::startTransfer()  //实现文件大小等信息的发送
{
    //这里的m_fileName是在selectFile中找到的,已经赋值了
    QString currentFileName = m_fileName.right(m_fileName.size() - m_fileName.lastIndexOf('/')-1);

    //最开始传输,写一下文件名
    if(fileName_flag == 0){
        //注意这里write的参数是QByteArray类型或者是const char*类型,
        //即要将QString转化为QByteArray用.toUtf8()
        //将QByteArray转化为const char*,用.data()
        m_tcpTextClient->write("&&&&");
        int flag = m_tcpTextClient->write(currentFileName.toUtf8());
        if(flag < 0){
             //ui->plainTextEdit->appendPlainText(QString("传送文件 %1 成功").arg(m_fileName));
            ui->plainTextEdit->appendPlainText(QString("传送文件 %1 失败").arg(m_fileName));
            exit(1);
        }
        ui->plainTextEdit->appendPlainText(QString("正在传送 %1 文件...").arg(m_fileName));
    }

    //文件名和文件内容需要分两次发送,看看别人的解决思路
    //github中的解决思路是:
    //发送端:读文件,进入循环发送文件,接收success信息,显示发送文件成功
    //接收端:F字母判断是接收文件,fopen打开文件的同时命名文件,进入循环,循环逻辑:recv以后fwrite文件,文件接收结束。给发送端发送success信息
    //接收两次,一次是文件名,一次是内容
    QFile file(m_fileName);
    bool isok = file.open(QIODevice::ReadWrite);
    qDebug() << "isok:" <<isok;

    //char buffer[1024];

    QFileInfo info(m_fileName);
    qDebug()<<"文件名字:"<< info.fileName();
    qDebug()<<"文件后缀:"<< info.suffix();
    qDebug()<<"文件大小:"<< info.size();
    qDebug()<<"文件创建时间:"<< info.created().toString("yyyy-MM-dd hh:mm:ss"); //yyyy代表年 MMd

    //发送文件大小
    m_tcpTextClient->write("&&&&");
    m_tcpTextClient->write(QByteArray::number(info.size()));
    m_tcpTextClient->waitForBytesWritten();


    if(isok){
        //用来存储文件内的内容
        QByteArray array;
        while(file.atEnd() == false){
            array += file.readLine();
            qDebug() << "readAll loop";
        }
        qDebug()<<"文件内容:"<< array;
        //输入分隔符,文件发送的格式为F&&&&文件名&&&&文件大小&&&&文件内容
        m_tcpTextClient->write("&&&&");
        //传输文件内容
        m_tcpTextClient->write(array);
    }


}


void MainWindow::on_btnSelectFile_clicked()
{
    m_fileName = QFileDialog::getOpenFileName(this, "选择文件");
    if (!m_fileName.isEmpty())
    {
        ui->plainTextEdit->appendPlainText(QString("打开文件 %1 成功!").arg(m_fileName));
        ui->btnSendFile->setEnabled(true);
    }

}

void MainWindow::onSocketStateChange(QAbstractSocket::SocketState socketState)
{//stateChange()信号槽函数
    switch(socketState)
    {
    case QAbstractSocket::UnconnectedState:
        m_labSocketState->setText("scoket状态:UnconnectedState");
        break;
    case QAbstractSocket::HostLookupState:
        m_labSocketState->setText("scoket状态:HostLookupState");
        break;
    case QAbstractSocket::ConnectingState:
        m_labSocketState->setText("scoket状态:ConnectingState");
        break;

    case QAbstractSocket::ConnectedState:
        m_labSocketState->setText("scoket状态:ConnectedState");
        break;

    case QAbstractSocket::BoundState:
        m_labSocketState->setText("scoket状态:BoundState");
        break;

    case QAbstractSocket::ClosingState:
        m_labSocketState->setText("scoket状态:ClosingState");
        break;

    case QAbstractSocket::ListeningState:
        m_labSocketState->setText("scoket状态:ListeningState");
    }
}

//下面是两个没有用到的槽函数(弃用)
void MainWindow::displayError(QAbstractSocket::SocketError) //显示错误
{
    ui->plainTextEdit->appendPlainText(m_tcpFileClient->errorString());
    m_tcpFileClient->close();
    ui->progressBar->reset();
}
// 更新进度条,实现文件的传送(弃用)
void MainWindow::updateClientProgress(qint64 numBytes)
{
    // 已经发送数据的大小
    m_bytesWritten += (int)numBytes;

    if(m_bytesToWrite > 0) // 剩余数据大小
    {
        // 从文件中取出数据到发送缓冲区,每次发送loadSize大小的数据,这里设置为4KB,如果剩余的数据不足4KB,就发送剩余数据的大小
        m_outBlock = m_localFile->read(qMin(m_bytesToWrite, m_loadSize));

        // 从发送缓冲区发送数据,计算发送完一次数据后还剩余数据的大小
        m_bytesToWrite -= (int)m_tcpFileClient->write(m_outBlock);

        // 清空发送缓冲区
        m_outBlock.resize(0);

    } else
    {
        m_localFile->close(); // 没有数据待发送,则关闭文件
    }

    //更新进度条
    ui->progressBar->setMaximum(m_totalBytes);
    ui->progressBar->setValue(m_bytesWritten);

    if(m_bytesWritten == m_totalBytes) //发送完毕
    {
        ui->plainTextEdit->appendPlainText(QString("传送文件 %1 成功").arg(m_fileName));
        m_localFile->close();
    }
}

mainwindow.h

c++ 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
//sql 要在.pro文件中加入sql
#include <QFile>
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
#include <QSqlRecord>

//server 要在.pro文件中加入network
#include <QTcpServer>
#include <QHostInfo>
#include <QTcpSocket>

#include <QSignalMapper>

#include<QDebug>
#include<QMessageBox>

//选择文件
#include <QFileDialog>

//时间
#include <QDateTime>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

protected slots:
    void onNewConnection();  //有新的请求会调用

    //void onSocketStateChange(QAbstractSocket::SocketState socketState);
    //显示连接状态 暂不需要,可通过stateChanged信号调用

    void onClientConnected(int);	//连接成功调用
    void onClientDisconnected(int);	//连接断开调用
    void onSocketReadyRead(int);	//有消息调用

    QSqlDatabase connectSql();

private slots:
    //文本读服务器的消息
    void onSocketReadyRead();
    //用来显示连接状态的槽函数
    void onSocketStateChange(QAbstractSocket::SocketState socketState);


    void onConnected();
    void onDisconnected();
    //连接动作
    void on_connectBt_clicked();
    void on_disconnectBt_clicked();
    //发送消息按钮,清空文本框按钮,选择文件按钮和发送文件按钮
    void on_btnSend_clicked();
    void on_clearBtn_clicked();
    void on_btnSelectFile_clicked();
    void on_btnSendFile_clicked();
    //发送文件大小等信息
    void startTransfer();

    //更新进度条,实现文件的传送(暂时没用到)
    void updateClientProgress(qint64 numBytes);
    void displayError(QAbstractSocket::SocketError);
private:
    Ui::MainWindow *ui;
    QSqlDatabase db; //数据库连接
    QTcpServer *tcpServer; //server连接
    QLabel* LabListenInfo; //状态栏显示正在连接
    QList <QTcpSocket *> tcpSocket;//TCP通信的Socket,消息格式为ip 端口号
    QList <bool> isfrist;       //判断是否第一条消息

    QString getLocalIP(); //得到本机ip

    //项目里的
    QTcpSocket  *m_tcpTextClient;  //文本消息socket
    QLabel  *m_labSocketState;  //状态栏显示标签
    QString m_fileName;  //保存文件路径

    //状态栏
    QLabel* labelStsInfo;               // 状态栏提示信息
    QLabel* labelStsIP;            // IP信息
    //发送文件需要的参数
    QFile *m_localFile;  //要发送的文件
    qint64 m_totalBytes;  //数据总大小
    qint64 m_bytesWritten;  //已经发送数据大小
    qint64 m_bytesToWrite;   //剩余数据大小
    qint64 m_loadSize;   //每次发送数据的大小
    QByteArray m_outBlock;  //数据缓冲区,即存放每次要发送的数据
    QTcpSocket  *m_tcpFileClient;  //文件消息socket



};
#endif // MAINWINDOW_H

服务端的cpp文件:

c++ 复制代码
#include <stdio.h>
#include<iostream>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <error.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <errno.h>

#include<map>
#include<fstream> 

using namespace std;
#define BUFFER_SIZE 1024

struct Client{
	int sockfd;
	string name;
	string fileName;
};


void writeText(map<int,Client> *client_map,char* buffer,int fd){
	cout << "unconvert buffer = " << buffer << endl;
	if((*client_map)[fd].name == ""){
		(*client_map)[fd].name = buffer+1;
		printf("(%d):%s,name:%s\n",__LINE__,__FUNCTION__,(*client_map)[fd].name.c_str());
	}else{
		//为了去除每次buffer前面的C字符
		string msg = buffer+1;
		string realmsg = '[' + (*client_map)[fd].name + ']' + msg;
		memset(buffer, 0, sizeof(buffer));
		strcpy(buffer, realmsg.c_str());
		cout << "realmsg:" <<realmsg << endl;
		cout << "buffer:" << buffer << endl;
		//转发给所有人,代码写到这儿了,还没有做好转发给所有人的功能
		for(auto it = (*client_map).begin(); it != (*client_map).end(); ++it){
			
			cout << "client_map.begin()->first=" << it->first << endl;
			// cout << "client_map.end()->first=" << (*client_map).end()->first << endl;
			printf("%s(%d):%s: server write buffer:%s\n", __FILE__, __LINE__, __FUNCTION__,buffer);
			printf("%s(%d):%s:sizeof(buffer):%d\n", __FILE__, __LINE__, __FUNCTION__,sizeof(*buffer));
			printf("%s(%d):%s:it->first:%d\n", __FILE__, __LINE__, __FUNCTION__,it->first);
			//这里的buffer是8个字节
			ssize_t write_result = write(it->first, buffer, BUFFER_SIZE);
			printf("(%d)write_result:%d \n", __LINE__ , write_result);
			if (write_result != BUFFER_SIZE) {
				printf("%s:server端写入失败\n",__FUNCTION__);
			}
		}
	}
}

void writeFile(map<int,Client> *client_map,char buffer[],int fd){
	printf("%s(%d):buffer:%s\n",__FUNCTION__,__LINE__,buffer);
	char file_name[512] = "";
	char file_size[64];
	const char *d = "&&&&";
	char *p;
	//第一次:F 不管
	p = strtok(buffer,d);
	//第二次 文件名
	strcpy(file_name,strtok(NULL,d));
	printf("second time:%s:%s\n",__FUNCTION__,file_name);
	FILE *fp = fopen(file_name,"w");
	if(fp == NULL){
		printf("无法写文件%s\n",file_name);
		exit(1);
	}
	//第三次 文件大小
	strcpy(file_size,strtok(NULL,d));
	int len = atoi(file_size);
	printf("third time:%s:%d\n",__FUNCTION__,len);
	//第四次 文件内容
	strcpy(buffer,strtok(NULL,d));//buffer没有问题
	printf("forth time:%s:%s\n",__FUNCTION__,buffer);

	//写文件
	//fseek(fp,0,SEEK_SET);	
	int flag = fwrite(buffer, sizeof(char), len, fp);
	if(flag < 0){
		printf("写入文件%s失败\n", file_name);
	}	

	fclose(fp);
}


void server103() {
	//设置参数
	int serv_sock, fileServ_sock ,cli_sock;
	struct sockaddr_in serv_addr, fileServ_addr ,cli_addr;
	socklen_t cliaddr_len = sizeof(cli_addr);

	//初始化
	serv_sock = socket(PF_INET, SOCK_STREAM, 0);
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = inet_addr("0.0.0.0");
	serv_addr.sin_port = htons(9527);


	//bind
	if (bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1) {
		printf("bind failed!\n");
	}

	//listen
	listen(serv_sock, 5);

	//使用epoll
	epoll_event event;
	int enfd, event_cnt;
	enfd = epoll_create(100);
	if (enfd == -1) {
		printf("epoll create failed! \n%d:%s", errno, strerror(errno));
		close(serv_sock);
		return;
	}
	//需要多个epoll_event,搞100个吧
	epoll_event* all_event = new epoll_event[100];
	
	//对epoll做初始化,将服务端用epoll添加进来
	event.events = EPOLLIN;
	//printf("EPOLLIN:%d\n", EPOLLIN);//结果为EPOLLIN:1
	event.data.fd = serv_sock;
	epoll_ctl(enfd, EPOLL_CTL_ADD, serv_sock, &event);

	char buffer[BUFFER_SIZE] = "";  //消息传输的buffer大小


	printf("开始进入while循环 \n");

	//保存客户端的消息
	map<int, Client> client_map;

	//对客户端传入后的epoll处理
	while (true) {
		event_cnt = epoll_wait(enfd, all_event, 100, 1000);
		//这里的event_cnt就是事件发生的数量,连接算一个,发送数据算一个
		printf("event_cnt: %d\n", event_cnt); //结果为0 0 0 1(有操作的时候) 0 0 0 1(有操作时)
		//sleep(1);
		if (event_cnt == -1) {
			printf("epoll wait failed! \n%d:%s", errno, strerror(errno));
			close(serv_sock);
			return;
		}
		if (event_cnt == 0) continue;
		for (int i = 0; i < event_cnt; i++) {
			int fd = all_event[i].data.fd;
			cout << "fd=" << fd << endl;

			if ( fd == serv_sock) {
				cli_sock = accept(serv_sock, (struct sockaddr*)&cli_addr, &cliaddr_len);
				if(cli_sock < 0){
					printf("accept error\n");
					continue;
				}
				//将客户端的socket加入epoll
				struct epoll_event ev_client;
				ev_client.events = EPOLLIN;
				ev_client.data.fd = cli_sock;
				int ret = epoll_ctl(enfd, EPOLL_CTL_ADD, cli_sock, &ev_client);
				if(ret < 0){
					printf("epoll_ctl error\n");
					break;
				}
				//printf("%s正在连接",cli_addr.sin_addr.s_addr);

				//保存该客户端的信息
				struct Client client;
				client.sockfd = cli_sock;
				client.name = "";
				client_map[cli_sock] = client;

				printf("已连接用户: %s:%d\n all_event[i].data.fd = %d\n", inet_ntoa(cli_addr.sin_addr),htons(cli_addr.sin_port),client_map[cli_sock].sockfd);
			}
			//这里写的逻辑不对,但还不知道怎么改:有头绪了,用C和F区分开消息和文件
			else{
				//这里read中的socket要写成all_event[i].data.fd,不是serv_sock		
				memset(buffer, 0, sizeof(buffer));
				ssize_t len = read(fd, buffer, sizeof(buffer));
				if (len <= 0) {
					//客户端断开连接了(或程序发生错误了),关掉客户端
					// printf("client closed,len < 0(%d)!\n", __LINE__);
					client_map.erase(fd);	
					epoll_ctl(enfd, EPOLL_CTL_DEL, fd, NULL);
					close(fd);
					printf("client is closed! fd = %d \n", fd);
					break;
				}
				else{
					printf("%s(%d):%s read buffer:%s\n", __FILE__, __LINE__, __FUNCTION__, buffer);
					//输出的时候带上自己的名字,三个参数:client_map,fd,buffer
					if(buffer[0] == 'C'){
						writeText(&client_map,buffer,fd);
					}else if(buffer[0] == 'F'){
						writeFile(&client_map,buffer,fd);
					}
				}
			}
		}
	}
	
	delete[]all_event;
	close(serv_sock);

}




int main(int argc,char* argv[])
{
	server103();
    
    return 0;
}
相关推荐
ULTRA??16 分钟前
C加加中的结构化绑定(解包,折叠展开)
开发语言·c++
凌云行者1 小时前
OpenGL入门005——使用Shader类管理着色器
c++·cmake·opengl
凌云行者1 小时前
OpenGL入门006——着色器在纹理混合中的应用
c++·cmake·opengl
~yY…s<#>1 小时前
【刷题17】最小栈、栈的压入弹出、逆波兰表达式
c语言·数据结构·c++·算法·leetcode
可均可可2 小时前
C++之OpenCV入门到提高004:Mat 对象的使用
c++·opencv·mat·imread·imwrite
白子寰2 小时前
【C++打怪之路Lv14】- “多态“篇
开发语言·c++
小芒果_012 小时前
P11229 [CSP-J 2024] 小木棍
c++·算法·信息学奥赛
gkdpjj3 小时前
C++优选算法十 哈希表
c++·算法·散列表
王俊山IT3 小时前
C++学习笔记----10、模块、头文件及各种主题(一)---- 模块(5)
开发语言·c++·笔记·学习
-Even-3 小时前
【第六章】分支语句和逻辑运算符
c++·c++ primer plus