欢迎光临
我们一直在努力

C++socket网络编程(跨平台)实战HTTP服务器(三)

             封装TCP类


封装一下tcp类, 步骤还可以简化,

直接放上代码类名:XTCP


xtcp.h

#ifndef _XTCP_H_
#define _XTCP_H_
#include <iostream>
#include <string.h>
class XTCP
{
public:
XTCP();
virtual ~XTCP();
public:
int CreateSocket();//创建socket 反悔socket
bool Bind(unsigned short port);//绑定端口
XTCP Accept();//反回一个对象
void Close();//关闭 主动做
int Recv(char *buf, int bufsize);//接收
int Send(const char *buf, int sendsize);//发送
int m_sock = 0;
unsigned short m_port = 0;
std::string ip;
};
#endif //_XTCP_H_

xtcp.cpp

#include "XTCP.h"
#ifdef WIN32
#include <Windows.h>
#define socklen_t int
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#define closesocket close
#include <string.h>
#endif
XTCP::XTCP()
{
#ifdef WIN32
static bool first = true; //保证只进入一次
if (first)
{
first = false;
WSADATA ws;
WSAStartup(MAKEWORD(2, 2), &ws);
}
#endif
}
XTCP::~XTCP()
{
}
int XTCP::CreateSocket()
{
m_sock = socket(AF_INET, SOCK_STREAM, 0);
if (m_sock == -1)
{
printf("create socket failed!\n");
}
return m_sock;
}
bool  XTCP::Bind(unsigned short port)
{
sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
sa.sin_addr.s_addr = htonl(0);
if (bind(m_sock, (sockaddr*)&sa, sizeof(sa)))
{
printf("bind port err\n");
//绑定成功
return false;
}
//侦听
listen(m_sock, 10);
//绑定失败
return true;
}
void XTCP::Close()
{
if (m_sock <= 0) return;
closesocket(m_sock);
}
XTCP XTCP::Accept()
{
XTCP tcp;
sockaddr_in sadd;
socklen_t len = sizeof(sadd);
printf("lsiteb ... accept ok\n");
//这里会阻塞 只有等待有新的连接 才会执行下面的代码
int client = accept(m_sock, (sockaddr*)&sadd, &len);
//反悔判断m_sock是否为0就行了
if (client <= 0)return tcp; 
printf("client connect ok\n");
//输出端口号和信息
tcp.ip = inet_ntoa(sadd.sin_addr);
//网络字节序转本地字节序哦
tcp.m_port = ntohs(sadd.sin_port);
//记录socket
tcp.m_sock = client;
printf("IP: %s:port: %d\n", tcp.ip.c_str(), tcp.m_port);
return tcp;
}
int XTCP::Recv(char *buf, int bufsize)
{
return recv(m_sock, buf, bufsize, 0);
}
int XTCP::Send(const char *buf, int sendsize)
{
//buf 必须发送制定大小   保证发送全部成功
int s = 0;  //以发送的  发送大小减去以及发送的
while (s != sendsize)
{
//反回就是发送的长度
int len = send(m_sock, buf + s, sendsize - s, 0);
if (len <= 0)
break;
s += len;  //加上发送的长度
}
return s;
}

测试代码

#include "XTCP.h"
#include <thread>
class TcpThread
{
public:
//线程入口函数 创建一个
void Main()
{
char buf[1024];
for (;;)
{
memset(buf, 0, sizeof(buf));
int recv_len = client.Recv( buf, sizeof(buf) - 1);
if (recv_len <= 0)break;
if (strstr(buf, "quit") != NULL)
{
char re[] = "quit success\n";
int sendlen = client.Send(re, strlen(re) + 1);
break;
}
char *p_ok = "ok\n";
int sendlen = client.Send(p_ok,strlen(p_ok));
printf("recv %s\n", buf);
}
client.Close();
delete this;
}
//用户的socket
XTCP client;
};

int main(int argc,char*argv[])
{
unsigned short port = 8016;
XTCP mytcp;
//创建
mytcp.CreateSocket();
//绑定
if (!mytcp.Bind(port))
return -1;
for (;;)
{
XTCP client = mytcp.Accept();
//创建线程
TcpThread *th = new TcpThread();
th->client = client;
std::thread sthr(&TcpThread::Main, th);
// 释放主线程占用的资源
sthr.detach();
}
mytcp.Close();
getchar();
return 0;
}

原理就是: 创建一个对象XTCP server,有一个int变量,是用来记录创建的socket.的,他用来和用户建立连接,然后服务器必须要绑定端口,Bind里自动侦听。(调用了listen函数)

然后就是反回一个用户client的XTCP对象,把这个对象赋值给上面

的线程类里的成员,应为他TcpThread*th = new TcpThread();

他里面有一个th->client = client; 把他赋值给这个client.

然后创建线程在线程里等待数据收发, 这个new的对象 是在

线程函数里进行释放的 也就是closesocket后面有一个delete this. ,最后就是th->detach() 是释放主线程占用的子线程

的资源,。



移植到linux

先看下makefile

SRC 添加main.cpp 和 XTCP.cpp 就行了

CC=g++
SRC=main.cpp XTCP.cpp
OBJ=hello.o
EXEC=manc
start:
        $(CC) $(SRC) -o $(EXEC) -std=c++11 -lpthread
$(OBJ):
        $(CC)  $(OBJ) -c $(SRC)
clean:
        rm -f $(OBJ) $(EXEC)
run:
        ./$(EXEC)

执行make start  编译连接

执行make run  执行

成功并发,多个客户端


        封装TCP类到Windowsd的dll动态库

将一个类封装到dll和linux的so

在这个博客里讲:

    http://12158490.blog.51cto.com/12148490/1947885












赞(0)
【声明】:本博客不参与任何交易,也非中介,仅记录个人感兴趣的主机测评结果和优惠活动,内容均不作直接、间接、法定、约定的保证。访问本博客请务必遵守有关互联网的相关法律、规定与规则。一旦您访问本博客,即表示您已经知晓并接受了此声明通告。