Linux下Socket編程(二)——多線程封裝

簡介

  • 客戶端連接后放到線程中運行
  • Socket相關代碼封裝

C++線程

這里使用c++11標準的線程庫。

#include <thread>

編譯時候出現

thread_1.png

根據錯誤提示編譯命令后加入-std=c++0x即可,對于使用的線程需要引入庫-lpthread

線程使用

線程的調用我們定義一個SocketThread類來進行

SocketThread* st=new SocketThread(connfd);
thread t(&SocketThread::run,st);
t.detach();

然后我們將數據讀取的方法放到SocketThread中

    void run(){
        int n=0;
        cout<<"new thread for socket "<<this->sock<<endl;
        char buff[1024];
        for(;; ) {
                n = recv(this->sock,buff,1024,0);
                if(n<=0) {
                        //如果客戶端斷開了,這里就跳出循環
                        break;
                }
                buff[n] = '\0';
                printf("%d=>%s",n,buff);
        }
        close(this->sock);
        cout<<this->sock<<" closed"<<endl;
    }
注意

當我么使用c++的語法,并使用std命名空間后發現客戶端連不上服務端。這里是bind方法出現了問題。使用了命名空間中的bind。這里需要是用全局的bind方法::bind即可。

Socket相關類封裝

這里我們將客戶端和服務的的操作封裝到一個類XTcp中,服務的接受連接后,生成一個新的Tcp對象,并將指針返回,然后線程類XThread持有XTcp的指針。

XTcp.h
#include <iostream>
using namespace std;

class XTcp{
private:
  int sock;

public:
  XTcp();
  void setSock(int sock);
  int getSock();
  int createSocket();
  int bindPort(unsigned short port);
  int listenSocket();
  int receive(char *buf,int len);
  int sendData(char *buf,int len);
  int connectServer(int port);
  XTcp* acceptClient();
  int closeSocket();
  ~XTcp();
};
XTcp.cpp
#include "XTcp.h"
#include "stdio.h"
//socket相關函數需要
#include <sys/types.h>
#include <sys/socket.h>
//close函數需要
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <errno.h>
#include <arpa/inet.h>
//c++ 11標準線程
#include <thread>
#include "XThread.h"
XTcp::XTcp(){
        sock=-1;
}

void XTcp::setSock(int sock){
        this->sock=sock;
}
int XTcp::getSock(){
        return this->sock;
}

int XTcp::createSocket(){
        //創建一個socket
        this->sock=socket(AF_INET,SOCK_STREAM,0);
        if(this->sock==-1) {
                cout<<"create socket failed"<<endl;
        }
        return this->sock;
}
int XTcp::bindPort(unsigned short port){
        struct sockaddr_in sockaddr;
        memset(&sockaddr,0,sizeof(sockaddr));
        sockaddr.sin_family=AF_INET;
        sockaddr.sin_addr.s_addr=htonl(INADDR_ANY);
        sockaddr.sin_port=htons(port);
        ::bind(sock,(struct sockaddr *)&sockaddr,sizeof(sockaddr));
        return 0;
}

/**
* 開始監聽
*/
int XTcp::listenSocket(){
        listen(sock,10);
        return 0;
}

/**
 *  接受客戶端的連接,如果連接成功就返回連接后的XTcp
 */
XTcp* XTcp::acceptClient(){
        int connfd;
        struct sockaddr_in sockaddrClient;
        int clientl=sizeof(sockaddrClient);
        printf("wait for client connect\n" );
        // if((connfd = accept(sock,NULL,NULL))==-1) {
        if((connfd = accept(sock,(struct sockaddr*)&sockaddrClient,(socklen_t *)&clientl))==-1) {
                printf("accpet socket error: %s errno :%d\n",strerror(errno),errno);
        }
        char cilentIp[20];
        unsigned short port= ntohs(sockaddrClient.sin_port);
        const char *ip=inet_ntop(AF_INET,(void *)&sockaddrClient.sin_addr,cilentIp,16);
        printf("client=> %s:%d\n",cilentIp,port);
        XTcp* xTcpClient=new XTcp;
        xTcpClient->setSock(connfd);
        //開啟線程接受數據
        XThread* st=new XThread(xTcpClient);
        thread t(&XThread::run,st);
        t.detach();
        return xTcpClient;
}

int XTcp::connectServer(int port){
        const char * serverIp="127.0.0.1";
        sockaddr_in sockaddr;
        memset(&sockaddr,0,sizeof(sockaddr));
        sockaddr.sin_family = AF_INET;
        sockaddr.sin_port = htons(port);
        //轉換ip地址
        inet_pton(AF_INET,serverIp,&sockaddr.sin_addr);
        if((connect(sock,(struct sockaddr*)&sockaddr,sizeof(sockaddr))) < 0 )
        {
                printf("connect error :[%s] errno: %d\n",strerror(errno),errno);
                exit(0);
        }
        cout<<"send msg to server:"<<endl;
        char buf[1024];
        while (true) {
                /* code */
                fgets(buf,1024,stdin);
                if(strcmp(buf,"exit\n")==0) {
                        //輸入exit后退出
                        break;
                }
                int size=sendData(buf,sizeof(buf));
                //寫數據是發生異常
                if(size<=0) {
                        break;
                }
        }
        //關閉客戶端socket
        closeSocket();
}

/*
 *  接受數據
 */
int XTcp::receive(char *buf,int len){
        int n = recv(this->sock,buf,len,0);
        return n;
}

/**
* 發送數據
*/
int XTcp::sendData(char *buf,int len){
        if(sock<0) {
                cout<<"socket is invalid"<<endl;
                return -1;
        }
        if(len<=0) {
                return 0;
        }
        int totalSize=0;
        while (totalSize<len) {
                /* code */
                int size=send(sock,buf+totalSize,strlen(buf)-totalSize,0);
                if(size<=0)
                        break;
                totalSize+=size;
        }
        return totalSize;
}

/**
 * 關閉socket
 */
int XTcp::closeSocket(){
        int ret=0;
        if(sock==-1) {
                cout<<"socket is not start"<<endl;
        }else if(sock==-1) {
                cout<<"socket have already closed"<<endl;
        }else{
                ret  =close(sock);
                if(ret==-1) {
                        printf("socket close failed\n");
                }else{
                        printf("%d close success!\n",sock );
                }
        }
        sock=-2;
        return ret;
}

XTcp::~XTcp(){
        cout<<"~XTcp"<<endl;
}
XThread.h
#include <iostream>
using namespace std;
class XThread {
private:
XTcp* sock;
public:
XThread(XTcp* sock){
        this->sock=sock;
}
~XThread(){
        cout<<"release"<<endl;
}
void run(){
        int n=0;
        cout<<"new thread for socket "<<this->sock->getSock()<<endl;
        char buff[1024];
        for(;; ) {
                n = sock->receive(buff,1024);
                if(n<=0) {
                        //如果客戶端斷開了,這里就跳出循環
                        break;
                }
                buff[n] = '\0';
                printf("%d=>%s",n,buff);
        }
        sock->closeSocket();
}
};
Makefile
all: xserver xclient

xserver : xserver.cpp XTcp.h XTcp.cpp XThread.h
    g++ -lpthread -o xserver xserver.cpp XTcp.cpp  -std=c++0x

xclient : xclient.cpp XTcp.h XTcp.cpp
    g++ -o $@ $+ -std=c++0x

.PHONY : clean
clean :
    -rm  xserver xclient
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,076評論 25 708
  • ———————————————回答好下面的足夠了---------------------------------...
    恒愛DE問候閱讀 1,753評論 0 4
  • 比較簡單,開門見山。 在andorid中,如果不做處理,EditText在獲得焦點鍵盤彈起之后,如果不做處理,則會...
    dlihasa閱讀 284評論 0 0
  • 【蘿鼓萱天】20170920 學習力踐行記錄 day128 1,英語。晚上點讀牛津樹五本,四舊一新。 2,數理。①...
    眸眸_50ae閱讀 204評論 0 0
  • 背景 在使用Vue開發時,遇到了這樣一個問題。如下所示: 問題分析 鎖定問題很明顯問題是fields屬性被重復聲明...
    王寶花閱讀 15,297評論 7 8