C++socket网络编程(跨平台)实战HTTP服务器(三)
封装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,如需转载请自行联系原作者