Service:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <strings.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> void *threadFunc(void *arg) { char cmd[5] = {0}; char fileHead[100] = {0}; char fileName[20]; int fileSize = 0; char buf[1024] = {0}; int fd; int connFd = *((int *)arg); //recv "pic" int ret = recv(connFd, cmd, sizeof(cmd), 0); if(ret < 0) { perror("recv error!"); close(connFd); return NULL; } if(0 == strcmp(cmd, "pic")) { //send fileHead strcpy(fileName, "roser.jpg"); struct stat stBuf = {0}; stat(fileName, &stBuf); fileSize = stBuf.st_size; sprintf(fileHead, "%s#%d", fileName, fileSize); ret = send(connFd, fileHead, sizeof(fileHead), 0); if(ret < 0) { perror("send error!"); close(connFd); return NULL; } //send file fd = open(fileName, O_RDONLY); if(fd < 0) { perror("open error!"); close(connFd); return NULL; } while(1) { memset(buf, 0, sizeof(buf)); ret = read(fd, buf, sizeof(buf)); if(ret < 0) { perror("read error!"); close(connFd); close(fd); return NULL; } else if(0 == ret) { break; } ret = send(connFd, buf, ret, 0); if(ret < 0) { perror("send error!"); close(connFd); close(fd); return NULL; } } } else { printf("cmd error!\n"); } close(connFd); close(fd); pthread_exit(NULL); } int main() { //1.socket int iServer = socket(AF_INET,SOCK_STREAM,0); if(iServer < 0) { perror("socket"); } printf("socket ok!\n"); //2.bind struct sockaddr_in stServer; stServer.sin_family = AF_INET; stServer.sin_port = htons(8888);//端口可以随便设置 stServer.sin_addr.s_addr = INADDR_ANY;//inet_addr("192.168.0.103"); int ret = bind(iServer,(struct sockaddr *)&stServer,sizeof(stServer)); if(ret < 0) { perror("bind"); } printf("bind ok!\n"); //3.listen ret = listen(iServer,5); if(ret < 0) { perror("listen"); } printf("listen ok!\n"); //4.accept struct sockaddr_in stClient; socklen_t len = sizeof(stClient); while(1) { printf("wait for a new client\n"); memset(&stClient,0,sizeof(stClient)); int iClient = accept(iServer,(struct sockaddr *)&stClient,&len); if(iClient < 0) { perror("accept"); return -1; } else { printf("accept ok!\n"); pthread_t th1; while(pthread_create(&th1,NULL,threadFunc,&iClient) != 0); pthread_detach(th1); } } //7.close close(iServer); return 0; }Client(Qt): widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QTcpSocket> namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); private slots: void on_connBtn_clicked(); void connectedSlot(); void on_getPicBtn_clicked(); void recvDataSlot(); void disConnectedSlot(); private: Ui::Widget *ui; QTcpSocket *socket; bool flag; QString fileName; int fileSize; QByteArray arr; }; #endif // WIDGET_Hmain.cpp
#include "widget.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); }widget.cpp
#include "widget.h" #include "ui_widget.h" #include <QHostAddress> #include <QDebug> Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); socket = new QTcpSocket(this); connect(socket, SIGNAL(connected()),this,SLOT(connectedSlot())); ui->getPicBtn->setEnabled(false); connect(socket,SIGNAL(readyRead()),this,SLOT(recvDataSlot())); connect(socket,SIGNAL(disconnected()),this,SLOT(disConnectedSlot())); flag = true; } Widget::~Widget() { delete ui; } void Widget::on_connBtn_clicked() { socket->connectToHost(QHostAddress("192.168.43.120"), 8888);//与上面的端口一致,ip为服务器的ip } void Widget::connectedSlot() { ui->connBtn->setEnabled(false); ui->getPicBtn->setEnabled(true); } void Widget::on_getPicBtn_clicked() { char cmd[5] = "pic"; socket->write(cmd, sizeof(cmd)); } void Widget::recvDataSlot() { qDebug() << "********"; if(true == flag) { char fileHead[100] = {0}; //接收文件头 socket->read(fileHead, sizeof(fileHead)); //解析文件头 QString str(fileHead); fileName = str.section('#', 0,0); fileSize = str.section('#',1,1).toInt(); flag = false; arr.clear(); } else { //只要flag不等于true,哪怕这个被调用很多次,也只会进入到这个分支 QByteArray arrTmp = socket->readAll(); arr.append(arrTmp); if(arr.size() >= fileSize) { //将文件显示在label上 flag = true; QPixmap pix; //将arr中的文件内容直接显示 bool ok = pix.loadFromData(arr); if(true == ok) { qDebug() << "load pic ok"; ui->label->setPixmap(pix); ui->label->setScaledContents(true); } } } } void Widget::disConnectedSlot() { ui->connBtn->setEnabled(true); ui->getPicBtn->setEnabled(false); }客户端界面如下:
虚拟机上运行:gcc -xxx.c -pthread -o 要生成的文件名
运行效果如下: Service端
客户端: