封装TCP类
封装一下tcp类, 步骤还可以简化,
直接放上代码类名:XTCP
xtcp.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
#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;
}
|
测试代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
#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 就行了
1
2
3
4
5
6
7
8
9
10
11
12
|
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
本文转自超级极客51CTO博客,原文链接:http://blog.51cto.com/12158490/1947886,如需转载请自行联系原作者