Linux學習筆記(五):網絡編程、QT信號與槽機制

突發疫情但擋不住我們學習的腳步,目前疫情好轉,宅了將近一個多月的自己終於可以出去戴着口罩出去走走了!!!
在這裏插入圖片描述

接上
Linux學習筆記(一)
Linux學習筆記(二)
Linux學習筆記(三):函數、文件IO和線程
Linux學習筆記(四):信息量、同步、互斥和網絡編程

複習

P操作 V操作

以下主要是對服務器和客戶端複習介紹:

1、服務器:server

//建立連接1socket( );//創建套接字
	聲明:int socket(int domain, int type,int protocol)
	int sock = socket(PF_INET,SOCK_STREAM,0;2bind( );//綁定自己的IP
	聲明:int bind(int sockfd, struct sockaddr *my_addr, int addrlen)
	bind(sock,(struct sockaddr*)(&myaddr),sizeof(myaddr));
		sockfd:是由socket調用返回的文件描述符.
		addrlen:是sockaddr結構的長度.
		my_addr:是一個指向sockaddr的指針. 在中有 sockaddr的定義
(3listen( );//監聽是否有客戶端向服務器發起連接
	聲明:int listen(int sockfd,int backlog)
		sockfd:是bind後的文件描述符.
		backlog:設置請求排隊的最大長度.當有多個客戶端程序和服務端相連時, 使用這個表示可以介紹的排隊長度. 函數將bind的文件描述符變爲監聽套接字.返回的情況和bind一樣.4accept( );//接受客戶端的請求
	聲明:int accept(int sockfd, struct sockaddr *addr,int *addrlen)
		sockfd:是listen後的文件描述符.
		addr,addrlen是用來給客戶端的程序填寫的,服務器端只要傳遞指針就可了. bind,listen和accept是服務器端用的函數, accept調用時,服務器端的程序會一直阻塞到有一個 客戶程序發出了連接. accept成功時返回最後的服務器端的文件描述符, 這個時候服務器端可以向該描述符寫信息了. 失敗時返回-1//接收數據5write( );//send( );6read( );//recv( );
//關閉7close( );

2、客戶端:client

//建立連接1socket( );2connect( );//主動發起與服務器的連接
	聲明:int connect(int sockfd, struct sockaddr * serv_addr,int addrlen)
		sockfd:socket返回的文件描述符.
		serv_addr:儲存了服務器端的連接信息.其中sin_add是服務端的地址
		addrlen:serv_addr的長度
		connect函數是客戶端用來同服務端連接的.成功時返回0,sockfd是同服務端通訊的文件描述符 失敗時返回-1.
//接收數據3read( );//recv();4write( );//send();
//關閉 5close( );

(1)網絡編程:

什麼是網絡編程呢?????
就是兩個進程,跨計算機,他倆需要通訊的話,需要通過網絡對接起來。這就是 socket 的作用。打個比方吧,兩個進程在兩個計算機上,需要有一個進程做被動方,叫做服務器。另一個做主動方,叫做客戶端。他們位於某個計算機上,叫做主機 host ,在網絡上有自己的 ip 地址。一個計算機上可以有多個進程作爲服務器,但是 ip 每個機器只有一個,所以通過不同的 port 數字加以區分。因此,服務器程序需要綁定在本機的某個端口號上。客戶端需要聲明自己連接哪個地址的那個端口。兩個進程通過網絡建立起通訊渠道,然後就可以通過 recv send 來收發一些信息,完成通訊。所以 socket 就是指代承載這種通訊的系統資源的標識。

通俗易懂的話轉自:https://www.zhihu.com/question/29637351/answer/110219546

客戶/服務器模式在TCP/IP網絡應用中,通信的兩個進程間相互作用的主要模式是客戶/服務器(Client/Server, C/S)模式,即客戶向服務器發出服務請求,服務器接收到請求後,提供相應的服務。
客戶/服務器模式的建立基於以下兩點:
(1)首先,建立網絡的起因是網絡中軟硬件資源、運算能力和信息不均等,需要共享,從而造就擁有衆多資源的主機提供服務,資源較少的客戶請求服務這一非對等作用。
(2)其次,網間進程通信完全是異步的,相互通信的進程間既不存在父子關係,又不共享內存緩衝區,因此需要一種機制爲希望通信的進程間建立聯繫,爲二者的數據交換提供同步,這就是基於客戶/服務器模式的TCP/IP。
在這裏插入圖片描述
服務器端:其過程是首先服務器方要先啓動,並根據請求提供相應服務:
(1)打開一通信通道並告知本地主機,它願意在某一公認地址上的某端口(如FTP的端口可能爲21)接收客戶請求;
(2)等待客戶請求到達該端口;
(3)接收到客戶端的服務請求時,處理該請求併發送應答信號。接收到併發服務請求,要激活一新進程來處理這個客戶請求(如UNIX系統中用fork、exec)。新進程處理此客戶請求,並不需要對其它請求作出應答。服務完成後,關閉此新進程與客戶的通信鏈路,並終止。
(4)返回第(2)步,等待另一客戶請求。
(5)關閉服務器

Server:
      int sock = socket(PF_INET,SOCK_STREAM,0);
      bind(sock,(struct sockaddr*)(&myaddr),sizeof(myaddr));
      struct sockaddr_in myaddr;
      myaddr.sin_family = PF_INET;
      myaddr.sin_port = htons(8888);
      myaddr.sin_addr.s_addr = inet_addr("192.168.13.119");
      listen(sock,7);
      int connfd = accept(sock,NULL,NULL);

客戶端
(1)打開一通信通道,並連接到服務器所在主機的特定端口;
(2)向服務器發服務請求報文,等待並接收應答;繼續提出請求;
(3)請求結束後關閉通信通道並終止。

client:
      connect(sock,(struct sockaddr*)(&seraddr),sizeof(seraddr));
      send(sock,”hello”,10,0);
      recv(sock,buf,sizeof(buf),0);
      close(sock);

1、服務器server接收和發送數據

創建套接字:Int sock = socket(PF_INET,SOCK_STREAM,0);
綁定自己的IP:bind(sock,(struct sockaddr*)(&myaddr),sizeof(myaddr));
主動發起與服務器的連接:struct sockaddr_in myaddr;
                      myaddr.sin_family = PF_INET;
                      myaddr.sin_port = htons(8888);
                      myaddr.sin_addr.s_addr = inet_addr("192.168.13.119");
監聽:listen(sock,7);
接受請求:int connfd = accept(sock,NULL,NULL);
發送數據:send(sock,”hello”,10,0);
接收數據:recv(sock,buf,sizeof(buf),0);

2、客戶端client接收和發送數據

發送數據:send(sock,”hello”,10,0);
接收數據:recv(sock,buf,sizeof(buf),0);

(2)QT編程學習

1、如何創建工程

特別需要注意的是linux下安裝QT需添加的環境配置
1、 在【終端】中執行如下命令:sudo gedit /etc/profile
2、添加如下內容:

針對32位的系統配置:

export QTDIR=/wyj/Qt5.4.1/5.4
export PATH=$QTDIR/gcc/bin:$PATH
export LD_LIBRARY_PATH=$QTDIR/gcc/lib:$LD_LIBRARY_PATH

針對64位的系統配置:

export QTDIR=/opt/Qt5.4.1/5.4
export PATH=$QTDIR/gcc_64/bin:$PATH
export LD_LIBRARY_PATH=$QTDIR/gcc_64/lib:$LD_LIBRARY_PATH

(1)打開Qt Creator,點擊New Project,創建一個新項目:Application->Qt Widgets Appliccation;
(2)項目名稱和創建路徑自己設置;
(3)Kit Selection選擇gcc交叉編譯器;
(4)如果系統沒有自帶openGL庫時,在做帶有3D效果的界面會報錯,手動安裝openGL。首先修改系統設置----軟件和更新----下載自----中國的服務器。

2、如何利用QT自帶函數創建按鍵接槽,文本顯示

信號和槽機制就相當於回調函數。在這種機制下,程序員有兩次處理事件的機會:

  1. 在捕獲事件後發射信號前進行預處理(事件不符合預期可以不發射信號)
  2. 在槽函數中進行主要處理
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpSocket>
#include <QMovie>
#include <QLineEdit>
#include "JasonQt/JasonQt_Vop.h"

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private slots:
	// 連接完成函數
    void connectDone();

    void recvdo();
	// 按鈕的槽函數
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();

    void on_pushButton_3_clicked();

    void on_pushButton_5_clicked();

    void on_pushButton_6_clicked();

    void on_pushButton_7_clicked();

    void on_pushButton_4_clicked();

    void on_pushButton_4_pressed();

    void on_pushButton_4_released();

private:
	// tcp連接函數
    void tcpConnect();
    bool Data_parsing(QByteArray);
private:
    Ui::Widget *ui;
    QTcpSocket tcpSocket,pic_socket;
    QMovie *movie;
    QLineEdit *line;
    JasonQt_Vop::BaiduVop m_baiduVop;
    unsigned int piclen;
    char picbuf[1024 * 1024 - 4];
};

#endif // WIDGET_H

2、如何利用UI自動手動創建按鍵和文本

在mainwindow.ui界面,添加一個pushbutton按鈕,如下
在這裏插入圖片描述
之後在新界面添加textEdit控件用來顯示要選擇的文件內容,選擇之後可以選擇layout佈局(點擊窗口空白部分,然後選擇界面上方的佈局方式)。

(3)案例學習

網絡編程:客戶端與服務器間的通信

ubuntu下利用ifconfig查看當前網絡下的IP地址。
打開兩個終端,分別運行服務器和客戶端的代碼:

服務器:

#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include <arpa/inet.h>
#include<unistd.h>

int main(){
    /*1.創建套i接字*/
   int sock = socket(PF_INET,SOCK_STREAM,0);
    if(sock < 0){
        printf("socket error\n");
        return -1;
    }
    printf("socket success\n");
    /*2.綁定本地IP*/
    struct sockaddr_in myaddr;
    myaddr.sin_family = PF_INET;
    myaddr.sin_port = htons(8888);// 設置端口號,我這裏設置的是8888
    myaddr.sin_addr.s_addr = inet_addr("xxx.xxx.xx.xxx");// 設置自己當前網端下的IP地址

    if(0 > bind(sock,(struct sockaddr*)(&myaddr),sizeof(myaddr))){
        printf("bind error\n");
        return -1;
    }
    printf("bind success\n");
    /*3.監聽*/
    if(0 > listen(sock,10)){
        printf("listen error\n");
        return -1;
    }
    printf("listen success\n");
    /*4.接受鏈接請求*/
    int connfd = accept(sock,NULL,NULL);
    if(connfd < 0){
        printf("accept error\n");
        return -1;
    }
    printf("accept success\n");
    /*5.數據收發*/
    //send()/recv();
    char buf[20];
    gets(buf);
    int ret = send(connfd,buf,sizeof(buf),0);
    if(ret < 0){
        printf("send error\n");
        return -1;
    }
    printf("send success\n");
    /*6.關閉套接字*/
    close(connfd);
    close(sock);
return 0;
}

客戶端:

#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include <arpa/inet.h>
#include<unistd.h>

int main(){
    /*1.創建套接字*/
   int sock = socket(PF_INET,SOCK_STREAM,0);
   if(sock < 0){
        printf("sock error\n");
        return -1;
    }
    printf("sock success\n");
    /*2.主動發起與服務器的連接*/
    struct sockaddr_in seraddr;
    seraddr.sin_family = PF_INET;
    seraddr.sin_port = htons(8888);
    seraddr.sin_addr.s_addr = inet_addr("xxx.xxx.xx.xxx");// 一定與服務器的IP地址一樣
    if(0 > connect(sock,(struct sockaddr*)(&seraddr),sizeof(seraddr))){
        printf("connect errorr\n");
        return -1;
    }
    printf("connect success\n");

    /*3.數據收發*/
    char buf[20];
   int ret = recv(sock,buf,sizeof(buf),0);
    if(ret < 0){
        printf("recv error\n");
        return -1;
    }
    printf("recv:%s\n",buf);
    /*4.關閉套接字*/
    close(sock);
    return 0;
}

運行結果:

在這裏插入圖片描述
可見服務器和客戶端之間的通信已見成效!!!!!!春暖花開
在這裏插入圖片描述

大家的三連擊是對我最大的肯定!!!大家不要吝嗇自己的鼠標或者手指。。。。。。

待續中。。。。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章