zoukankan      html  css  js  c++  java
  • QT 网络编程三(TCP版)

    QT客户端
    //widget.h
    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include <QWidget>
    #include <QTcpSocket>
    #include <QPushButton>
    #include <QLineEdit>
    #include <QLabel>
    #include <QCloseEvent>
    #include <QTextBrowser>
    
    
    class Widget : public QWidget
    {
        Q_OBJECT
    
    public:
        Widget(QWidget *parent = 0);
        ~Widget();
    private:
        QTcpSocket *tcpsocket;
        QPushButton *btn1,*btn2;
        QLineEdit *edit1,*edit2,*edit3;
        QLabel *label1,*label2,*label3;
        QTextBrowser *textb;
    
        void closeEvent(QCloseEvent *event);
    private slots:
        void btn1_click();
        void btn2_click();
        void myrecvdata();
    };
    
    #endif // WIDGET_H
    //widget.cpp
    #include "widget.h"
    #include <QHBoxLayout>
    #include <QVBoxLayout>
    #include <QMessageBox>
    #include <QHostAddress>
    
    Widget::Widget(QWidget *parent)
        : QWidget(parent)
    {
        tcpsocket=new QTcpSocket(this);
        btn1=new QPushButton(tr("连接"));
        btn2=new QPushButton(tr("发送"));
        connect(btn1,SIGNAL(clicked()),this,SLOT(btn1_click()));
        connect(btn2,SIGNAL(clicked()),this,SLOT(btn2_click()));
        edit1=new QLineEdit();
        edit2=new QLineEdit();
        edit3=new QLineEdit();
        label1=new QLabel(tr("IP地址:"));
        label2=new QLabel(tr("端口号:"));
        label3=new QLabel(tr("消息内容:"));
        textb=new QTextBrowser();
        QHBoxLayout *lay1=new QHBoxLayout();
        lay1->addWidget(label1);
        lay1->addWidget(edit1);
        lay1->addWidget(label2);
        lay1->addWidget(edit2);
        lay1->addWidget(btn1);
        QHBoxLayout *lay2=new QHBoxLayout();
        lay2->addWidget(label3);
        lay2->addWidget(edit3);
        lay2->addWidget(btn2);
        QHBoxLayout *lay4=new QHBoxLayout();
        lay4->addWidget(textb);
        QVBoxLayout * lay3=new QVBoxLayout(this);
        lay3->addLayout(lay1);
        lay3->addLayout(lay2);
        lay3->addLayout(lay4);
        /*接收数据*/
        connect(tcpsocket,SIGNAL(readyRead()),this,SLOT(myrecvdata()));
    }
    
    //连接
    void Widget::btn1_click()
    {
        /*禁用按钮,值是false*/
        btn1->setEnabled(false);
        //获取IP地址
        QString ipaddr=edit1->text();
        edit1->setEnabled(false);
        //获取端口号
        QString port=edit2->text();
        edit2->setEnabled(false);
        QHostAddress * serverip=new QHostAddress();
        serverip->setAddress(ipaddr);
        tcpsocket->connectToHost(*serverip,port.toInt());
        //释放socket连接
        delete serverip;
    }
    
    //发送
    void Widget::btn2_click()
    {
        QString strtext=edit3->text();
        if(!strtext.isEmpty())
            tcpsocket->write(strtext.toStdString().data());
        /*清空输入框*/
        edit3->clear();
        /*设置输入框重新获得焦点*/
        edit3->setFocus();
    }
    
    //接收消息
    void Widget::myrecvdata()
    {
        char buf[1024]={0};
        /*bytesAvailable()表示有效数据*/
        while(tcpsocket->bytesAvailable()>0)
        {
            memset(buf,0,sizeof(buf));
            tcpsocket->read(buf,sizeof(buf));
            textb->append(buf);
            //QMessageBox::information(this,"消息",buf);
        }
    }
    
    //关闭
    void Widget::closeEvent(QCloseEvent *event)
    {
        if(QMessageBox::question(this,"提示","你确定要退出程序吗?",QMessageBox::Yes|QMessageBox::No,QMessageBox::No)==QMessageBox::Yes)
        {
            event->accept();
        }else
        {
            event->ignore();
        }
    }
    
    Widget::~Widget()
    {
    
    }
    Linux服务器端
    //pub.h
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <errno.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <fcntl.h>
    #include <sys/select.h>
    #include <sys/time.h>
    
    #define MAXPondNum 100
    
    #ifdef __cplusplus
    extern "C"
    {
    #endif
    
    //create socket
    int create_socket(int port);
    
    //set noblock
    int setnonblock(int st);
    
    //select
    int open_select(int st);
    
    #ifdef __cplusplus
    extern "C"
    }
    #endif
    //pub.c
    #include "pub.h"
    
    //create socket
    int create_socket(int port)
    {
        if (port <= 0)
        {
            printf("create_socket() param not correct!
    ");
            return -1;
        }
        int st = socket(AF_INET, SOCK_STREAM, 0);
        if (st < 0)
        {
            printf("socket() failed ! error message:%s
    ", strerror(errno));
            return -1;
        }
        //reuse address
        int on = 1;
        if (setsockopt(st, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
        {
            printf("socket() failed ! error message:%s
    ", strerror(errno));
            close(st);
            return -1;
        }
        //bind
        struct sockaddr_in addr;
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
        if (bind(st, (struct sockaddr *) &addr, sizeof(addr)) < 0)
        {
            printf("bind() failed ! error message:%s
    ", strerror(errno));
            close(st);
            return -1;
        }
        //listen
        if (listen(st, 100) < 0)
        {
            printf("listen() failed ! error message:%s
    ", strerror(errno));
            close(st);
            return -1;
        }
        return st;
    }
    
    //set noblock
    int setnonblock(int st)
    {
        if (st < 0)
        {
            printf("setnonblock() param not correct!
    ");
            return -1;
        }
        int opts = fcntl(st, F_GETFL);
        if (opts < 0)
        {
            printf("fcntl() failed ! error message:%s
    ", strerror(errno));
            return -1;
        }
        opts = opts | O_NONBLOCK;
        if (fcntl(st, F_SETFL, opts))
        {
            printf("fcntl() failed ! error message:%s
    ", strerror(errno));
            return -1;
        }
        return opts;
    }
    
    //net address to
    int sockaddrtoa(const struct sockaddr_in *addr, char *ipaddr)
    {
        if (addr == NULL || ipaddr == NULL)
        {
            printf("sockaddrtoa() param not correct!
    ");
            return -1;
        }
        unsigned char *p = (unsigned char *) &(addr->sin_addr.s_addr);
        sprintf(ipaddr, "%u:%u:%u:%u", p[0], p[1], p[2], p[3]);
        return 0;
    }
    
    //accept clinet
    int accept_client(int st)
    {
        if (st < 0)
        {
            printf("accept_client() param not correct!
    ");
            return -1;
        }
        struct sockaddr_in addr;
        memset(&addr, 0, sizeof(addr));
        socklen_t len = sizeof(addr);
        int client_st = accept(st, (struct sockaddr *) &addr, &len);
        if (client_st < 0)
        {
            printf("accept() failed ! error message:%s
    ", strerror(errno));
            return -1;
        }
        char ipstr[100] = { 0 };
        sockaddrtoa(&addr, ipstr);
        printf("accept by %s
    ", ipstr);
        return client_st;
    }
    
    //recv message
    int recv_message(int st)
    {
        if (st < 0)
        {
            printf("accept_client() param not correct!
    ");
            return -1;
        }
        char buf[1024]={0};
        int rc=recv(st,buf,sizeof(buf),0);
        if(rc<0)
        {
            printf("recv() failed ! error message:%s
    ",strerror(errno));
            return -1;
        }else if(rc==0)
        {
            /*这里需要判断客户端是不是关闭连接了*/
            printf("client is closed!
    ");
            return -1;
        }
        printf("%s
    ",buf);
        //发送接收信息
        memset(buf,0,sizeof(buf));
        strcpy(buf,"server have recved !
    ");
        if(send(st,buf,sizeof(buf),0)<0)
        {
            printf("send() failed ! error message:%s
    ",strerror(errno));
            return -1;
        }
        return 0;
    }
    
    //select
    int open_select(int st)
    {
        if (st < 0)
        {
            printf("open_select() param not correct!
    ");
            return -1;
        }
        int i = 0;
        /*池子中只存放客户端socket*/
        int socketpond[MAXPondNum] = { 0 };
        /*
         * 注意int socketpond[MAXPondNum] = { -1 };
         * 改写法并不能将所有元素初始化为-1,只有0这种唯一特例
         * */
        for(i=0;i<MAXPondNum;i++)
        {
            socketpond[i]=-1;
        }
        /*定义事件数组中socket最大的值*/
        int maxfd = 0;
        /*准备监听事件数组结构*/
        fd_set allsocket;
        while (1)
        {
            /*清空有消息的事件数组*/
            FD_ZERO(&allsocket);
            /*将服务器socket直接放入事件数组中*/
            FD_SET(st, &allsocket);
            /*假设服务器socket是事件数组中最大的*/
            maxfd = st;
            /*遍历现有socket池,找出最大的socket,将所有的socket添加到事件数组中*/
            for (i = 0; i < MAXPondNum; i++)
            {
                if (socketpond[i] != -1)
                {
                    FD_SET(socketpond[i], &allsocket);
                    if (socketpond[i] > maxfd)
                    {
                        maxfd = socketpond[i];
                    }
                }
            }
            int events = select(maxfd + 1, &allsocket, NULL, NULL, NULL);
            if (events < 0)
            {
                printf("select() failed ! error message:%s
    ", strerror(errno));
                break;
            }
            /*
             * 猜想:当两个客户端同时连接到服务器时,select是如何处理服务器socket事件的呢
             * 我认为一个服务器端socket只能处理一个客户端连接请求
             * 事件数组中只有一个服务器socket,这个服务器socket只会处理一个客户端连接请求,
             * 而此时另外一个客户端请求会在下次的select事件数组中被处理
             * */
            /*先处理服务器socket特殊处理*/
            if (FD_ISSET(st, &allsocket))
            {
                printf("accept client!
    ");
                //accept
                int client_st = accept_client(st);
                if (client_st < 0)
                {
                    break;
                }
                //set nonblock
                if (setnonblock(client_st) < 0)
                {
                    break;
                }
                for (i = 0; i < MAXPondNum; i++)
                {
                    if (socketpond[i] == -1)
                    {
                        socketpond[i] = client_st;
                        break;
                    }
                }
                if (i == MAXPondNum)
                {
                    printf("服务端连接池已满!
    ");
                    close(client_st);
                }
            }
            for (i = 0; i < MAXPondNum; i++)
            {
                if (socketpond[i] < 0)
                {
                    continue;
                }
                if (FD_ISSET(socketpond[i], &allsocket))
                {
                    //接收客户端发送消息
                    if(recv_message(socketpond[i])<0)
                    {
                        //接收客户端消息出错
                        //关闭客户端
                        close(socketpond[i]);
                        //从服务器端socket池子中将该socket清除
                        socketpond[i]=-1;
                    }
                    /*需要处理的事件数减一*/
                    events--;
                }
                if(events<0)
                {
                    break;
                }
            }
        }
        return 0;
    }
    //mserver.c
    //服务器端
    #include "pub.h"
    
    int main(int arg,char *args[])
    {
        if(arg<2)
        {
            printf("please print one param!
    ");
            return -1;
        }
        int port=atoi(args[1]);
        int listen_st=create_socket(port);
        if(listen_st<0)
            return -1;
        if(setnonblock(listen_st)<0)
            goto END;
        open_select(listen_st);
        END:close(listen_st);
        return 0;
    }
    .SUFFIXES:.c .o
    CC=gcc
    SRCS=mserver.c
        pub.c
    OBJS=$(SRCS:.c=.o)
    EXEC=mser
    start:$(OBJS)
        $(CC) -o $(EXEC) $(OBJS)
        @echo "-------OK--------"
    .c.o:
        $(CC) -g -Wall -o $@ -c $<
    clean:
        rm -f $(OBJS)
        rm -f $(EXEC)

  • 相关阅读:
    interbase C++Builder 简单例子
    delphi代码实现创建dump文件
    在Mac OSX下使用ssh建立隧道(在Windows下建立隧道可以使用putty,其间会用到ppk文件)
    为什么豌豆荚们没能成为伟大的公司?
    解读雷军演讲,小米能否借“科技业的无印良品”反弹?(坚硬和纯洁的心,才能把这个事情干好)
    SOCKET网络编程5
    SQL Server 跨网段(跨机房)复制
    Erlang千万级用户游戏框架(Openpoker)源码文件分析清单
    异步编程
    代码性能不高
  • 原文地址:https://www.cnblogs.com/zhanggaofeng/p/6015467.html
Copyright © 2011-2022 走看看