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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,401评论 25 707
  • ———————————————回答好下面的足够了---------------------------------...
    恒爱DE问候阅读 1,710评论 0 4
  • 比较简单,开门见山。 在andorid中,如果不做处理,EditText在获得焦点键盘弹起之后,如果不做处理,则会...
    dlihasa阅读 277评论 0 0
  • 【萝鼓萱天】20170920 学习力践行记录 day128 1,英语。晚上点读牛津树五本,四旧一新。 2,数理。①...
    眸眸_50ae阅读 195评论 0 0
  • 背景 在使用Vue开发时,遇到了这样一个问题。如下所示: 问题分析 锁定问题很明显问题是fields属性被重复声明...
    王宝花阅读 15,217评论 7 8