前言
以前写tcp的socket操作,都是从头写。
这次维护的cm中要加入新的socket客户端和sokcet服务器的操作,工程中有一部分简单封装的socket函数,封装的不是很好,看着较为难受,而且封装的不全,只有客户端的socket操作。
如果要加入风格不统一的socket封装,写逻辑代码时,必定很难受。主要是弄的心很乱,不能忍。
想重新封装一个好用的tcp的socket操作类,然后将工程旧的socket封装函数都砍掉,换上封装后的socket类。
我给这个工程起名叫tcp_socket_easy, 希望心随所愿:)
封装完后,用起来确实很方便。
基类为socket_base,子类有2个:socket_tcp_client, socket_tcp_server.
不用封到类中的socket函数,放到socket_helper.h。
经过封装后,代码整洁多了。
在工程中自包含了客户端和服务器端的测试代码,用命令行隔开,一个工程就可以当作客户端或服务器。
工程在windows和linux下均有工程文件,都可以编译并运行。
仅进行了类接口的测试,如果要加入现有工程,只需要调整下接口调用的逻辑(e.g. 服务器接受客户端连接后,要开一个线程来处理,服务器继续接受客户端连接)。本工程仅是封装tcp的socket操作,只展现这一个点。
工程下载点
编译测试环境
windows环境: win10x64 + vs2010vc++
linux环境: rh5.4x64 + g++
测试工程的效果
[root@localhost src]# ./tcp_socket_easy -server
--------------------------------------------------------------------------------
tcp_socket_easy 1.0.0.1 2017-12-5 21:31
--------------------------------------------------------------------------------
>> server_proc
client coming : :
server.recv_until_over : hello, i'm client
<< server_proc
--------------------------------------------------------------------------------
THE END
--------------------------------------------------------------------------------
[root@localhost src]# ./tcp_socket_easy -client
--------------------------------------------------------------------------------
tcp_socket_easy 1.0.0.1 2017-12-5 21:31
--------------------------------------------------------------------------------
>> client_proc
!client.is_connect_ok()
client.connect("127.0.0.1", 54321, 1) = true
client.recv_until_over : hello, i'm server
<< client_proc
--------------------------------------------------------------------------------
THE END
--------------------------------------------------------------------------------
工程预览
socket_easy实现
// @file socket_base.h
#ifndef __SOCKET_BASE_H__
#define __SOCKET_BASE_H__
#include "socket_helper.h"
NS_SOCKET_EASY_BEGIN
class socket_base {
public:
socket_base();
virtual ~socket_base();
virtual const char* get_class_name() = 0;
void set_socket_handle(SOCKET sk) {m_socket = sk;}
SOCKET& get_socket_handle() {return m_socket;}
int generate_new_socket(int family, int type, int protocol);
void close_socket_handle(); // 要在析构中调用,不能为虚
void close_socket_handle(SOCKET sk);
void save_last_error();
int get_last_error() {return m_i_last_error;}
const char* get_last_error_string() {return strerror(get_last_error());}
int send_until_over(SOCKET sk, char * buf, int buf_len);
int recv_until_over(SOCKET sk, char * buf, int buf_len);
private:
int send_one_time(SOCKET sk, char * data, int data_len);
int recv_one_time(SOCKET sk, char * data, int data_len);
private:
SOCKET m_socket;
int m_i_last_error;
};
NS_SOCKET_EASY_END
#endif // #ifndef __SOCKET_BASE_H__
// @file socket_tcp_client.h
#ifndef __SOCKET_TCP_CLIENT_H__
#define __SOCKET_TCP_CLIENT_H__
#include "socket_base.h"
NS_SOCKET_EASY_BEGIN
class socket_tcp_client : public socket_base {
public:
socket_tcp_client();
virtual ~socket_tcp_client();
void close_socket_handle();
virtual const char* get_class_name();
bool connect(const char * ip, const int port, int time_out_s);
bool is_connect_ok();
private:
bool m_b_socket_connect_ok;
};
NS_SOCKET_EASY_END
#endif // #ifndef __SOCKET_TCP_CLIENT_H__
// @file socket_tcp_server.h
#ifndef __SOCKET_TCP_SERVER_H__
#define __SOCKET_TCP_SERVER_H__
#include "socket_base.h"
NS_SOCKET_EASY_BEGIN
class socket_tcp_server : public socket_base {
public:
socket_tcp_server();
virtual ~socket_tcp_server();
void close_socket_handle();
void close_socket_handle(SOCKET sk);
virtual const char* get_class_name();
bool listen_local_port(int iport);
SOCKET accept_client(std::string& str_client_ip, std::string& str_client_port);
private:
SOCKET accept_ex(SOCKET fd, struct sockaddr* sa, socklen_t* salenptr);
bool bind_ex(SOCKET fd, const struct sockaddr* sa, socklen_t salen);
bool listen_ex(SOCKET fd, int backlog);
};
NS_SOCKET_EASY_END
#endif // #ifndef __SOCKET_TCP_SERVER_H__
// @file socket_helper.h
#ifndef __SOCKET_HELPER_H__
#define __SOCKET_HELPER_H__
#include <sys/types.h> /* See NOTES */
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <string.h>
#ifndef WIN32
// linux
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <strings.h> // for bzero
#else
// win
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#include <windows.h>
#include <ws2tcpip.h> // for socklen_t
#endif // #ifndef WIN32
#ifndef INVALID_SOCKET
#define INVALID_SOCKET (~0)
#endif
#ifndef SOCKET_ERROR
#define SOCKET_ERROR (-1)
#endif
#ifndef WIN32
// linux env
#ifndef SOCKET
typedef int SOCKET;
#endif // #ifndef SOCKET
#endif // #ifndef WIN32
#define NS_SOCKET_EASY ls
#define NS_SOCKET_EASY_BEGIN namespace NS_SOCKET_EASY {
#define NS_SOCKET_EASY_END }
NS_SOCKET_EASY_BEGIN
#ifndef WIN32
// linux
#else
// win
void bzero(void *dst, size_t n);
#endif // #ifndef WIN32
int thread_env_socket_init();
int thread_env_socket_uninit();
bool safe_close_socket(SOCKET& sk);
NS_SOCKET_EASY_END
#endif // #ifndef HELPER
// @file socket_base.cpp
#include "socket_base.h"
NS_SOCKET_EASY_BEGIN
socket_base::socket_base() {
m_socket = INVALID_SOCKET;
m_i_last_error = -1;
}
socket_base::~socket_base() {
close_socket_handle();
}
void socket_base::save_last_error()
{
#ifndef WIN32
m_i_last_error = errno;
#else
m_i_last_error = WSAGetLastError();
#endif // #ifndef WIN32
}
int socket_base::generate_new_socket(int family, int type, int protocol)
{
int i_port_re_use = 1; // enable : socket addr re use
SOCKET i_sock_sn = INVALID_SOCKET;
i_sock_sn = socket(family, type, protocol);
if (i_sock_sn < 0) {
save_last_error();
} else {
// reuse port !
setsockopt(i_sock_sn, SOL_SOCKET, SO_REUSEADDR, (const char*)&i_port_re_use, sizeof(i_port_re_use));
}
return i_sock_sn;
}
int socket_base::send_one_time(SOCKET sk, char * data, int data_len) {
int i_rc = 0;
try {
i_rc = ::send(sk, data, data_len, 0);
if (SOCKET_ERROR == i_rc) {
save_last_error();
}
} catch (...) {
i_rc = -1;
}
return i_rc;
}
int socket_base::send_until_over(SOCKET sk, char * buf, int buf_len) {
int i_rc = 0;
int len = 0;
while (buf_len > 0) {
i_rc = send_one_time(sk, buf + len, buf_len);
if (i_rc < 0) {
break;
}
len += i_rc;
buf_len -= i_rc;
}
return len;
}
int socket_base::recv_one_time(SOCKET sk, char * data, int data_len) {
int i_rc = 0;
i_rc = ::recv(sk, data, data_len, 0);
if (SOCKET_ERROR == i_rc) {
save_last_error();
}
return i_rc;
}
int socket_base::recv_until_over(SOCKET sk, char * buf, int buf_len) {
int i_rc = 0;
int len = 0;
while (buf_len > 0) {
i_rc = recv_one_time(sk, buf + len, buf_len);
if (i_rc < 0) {
break;
}
len += i_rc;
buf_len -= i_rc;
}
return len;
}
void socket_base::close_socket_handle()
{
close_socket_handle(get_socket_handle());
m_i_last_error = -1;
}
void socket_base::close_socket_handle(SOCKET sk)
{
safe_close_socket(sk);
}
NS_SOCKET_EASY_END
// @file socket_tcp_client.cpp
#include "socket_tcp_client.h"
NS_SOCKET_EASY_BEGIN
socket_tcp_client::socket_tcp_client()
{
m_b_socket_connect_ok = false;
}
socket_tcp_client::~socket_tcp_client()
{
close_socket_handle();
}
const char* socket_tcp_client::get_class_name()
{
return "socket_tcp_client";
}
void socket_tcp_client::close_socket_handle()
{
socket_base::close_socket_handle();
m_b_socket_connect_ok = false;
}
bool socket_tcp_client::connect(const char * ip, const int port, int time_out_s)
{
bool b_rc = false;
int i_rc = 0;
SOCKET sk = INVALID_SOCKET;
sockaddr_in addr;
do {
if ((NULL == ip) || (port < 0)) {
break;
}
if ((SOCKET)INVALID_SOCKET == get_socket_handle()) {
set_socket_handle(generate_new_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
if ((SOCKET)INVALID_SOCKET == get_socket_handle()) {
break;
}
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip);
addr.sin_port = htons(port);
// convert a text host address to a numeric address
if (inet_pton(AF_INET, (char *)ip, &addr.sin_addr) <= 0) {
break;
}
// set recv timeout
timeval tv;
tv.tv_sec = time_out_s;
tv.tv_usec = 0;
setsockopt(get_socket_handle(), SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, sizeof tv);
// connect server port
m_b_socket_connect_ok = false;
i_rc = ::connect(get_socket_handle(), (struct sockaddr*) &addr, sizeof(addr));
if (SOCKET_ERROR == i_rc) {
save_last_error();
close_socket_handle();
break;
}
m_b_socket_connect_ok = true;
b_rc = m_b_socket_connect_ok;
} while (0);
return b_rc;
}
bool socket_tcp_client::is_connect_ok()
{
return (((int)INVALID_SOCKET != get_socket_handle()) && m_b_socket_connect_ok);
}
NS_SOCKET_EASY_END
// @file socket_tcp_server.cpp
#include "socket_tcp_server.h"
NS_SOCKET_EASY_BEGIN
socket_tcp_server::socket_tcp_server()
{
}
socket_tcp_server::~socket_tcp_server()
{
close_socket_handle();
}
const char* socket_tcp_server::get_class_name()
{
return "socket_tcp_server";
}
void socket_tcp_server::close_socket_handle()
{
socket_base::close_socket_handle();
}
void socket_tcp_server::close_socket_handle(SOCKET sk)
{
socket_base::close_socket_handle(sk);
}
SOCKET socket_tcp_server::accept_ex(SOCKET fd, struct sockaddr* sa, socklen_t* salenptr)
{
SOCKET sk = INVALID_SOCKET;
do {
sk = ::accept(fd, sa, salenptr);
if (sk < 0) {
if ((ECONNABORTED == errno) || (EINTR == errno))
continue;
else {
save_last_error();
break;
}
}
break;
} while (1);
return sk;
}
bool socket_tcp_server::bind_ex(SOCKET fd, const struct sockaddr* sa, socklen_t salen)
{
int i_rc = 0;
i_rc = ::bind(fd, sa, salen);
if (i_rc < 0) {
save_last_error();
}
return (0 == i_rc);
}
bool socket_tcp_server::listen_ex(SOCKET fd, int backlog)
{
int i_rc = 0;
i_rc = ::listen(fd, backlog);
if (i_rc < 0) {
save_last_error();
}
return (0 == i_rc);
}
bool socket_tcp_server::listen_local_port(int iport)
{
bool b_rc = false;
addrinfo hints;
addrinfo* res = NULL;
struct sockaddr_in server_addr;
SOCKET listenfd = INVALID_SOCKET;
char sz_buf[0x1000] = {'\0'};
std::string str_server_port = "";
memset(&hints, 0, sizeof(struct addrinfo));
do {
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
sprintf(sz_buf, "%d", iport);
str_server_port = sz_buf;
if (0 != getaddrinfo(NULL, str_server_port.c_str(), &hints, &res))
{
save_last_error();
break;
}
freeaddrinfo(res);
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(iport);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
listenfd = generate_new_socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == listenfd) {
break;
}
set_socket_handle(listenfd);
if (!bind_ex(get_socket_handle(), (struct sockaddr*)&server_addr, sizeof(server_addr))) {
break;
}
if (!listen_ex(get_socket_handle(), SOMAXCONN)) {
break;
}
b_rc = true;
} while (0);
return b_rc;
}
SOCKET socket_tcp_server::accept_client(std::string& str_client_ip, std::string& str_client_port)
{
int i_rc = 0;
SOCKET i_fd = INVALID_SOCKET;
int clientlen = 0;
struct sockaddr_in client_addr;
sockaddr_storage clientaddr;
char clienthost[NI_MAXHOST] = {'\0'};
char clientservice[NI_MAXSERV] = {'\0'};
clientlen = sizeof(client_addr);
bzero(&client_addr, sizeof(client_addr));
str_client_ip = "";
str_client_port = "";
do {
i_fd = accept_ex(get_socket_handle(), (struct sockaddr*)&client_addr, (socklen_t*)&clientlen);
if (INVALID_SOCKET == i_fd) {
break;
}
i_rc = getnameinfo((sockaddr *)&clientaddr,
clientlen,
clienthost,
sizeof(clienthost),
clientservice,
sizeof(clientservice),
NI_NUMERICHOST|NI_NUMERICSERV);
if (0 == i_rc) {
str_client_ip = clienthost;
str_client_port = clientservice;
}
} while (0);
return i_fd;
}
NS_SOCKET_EASY_END
// @file socket_helper.cpp
#include "socket_helper.h"
NS_SOCKET_EASY_BEGIN
#ifndef WIN32
// linux
#else
// win
void bzero(void *dst, size_t n)
{
memset(dst, 0, n);
}
#endif // #ifndef WIN32
int thread_env_socket_init()
{
#ifndef WIN32
#else
// win
int iRc = 0;
WSADATA wsaData;
iRc = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (NO_ERROR != iRc)
{
// err
}
#endif
return 0;
}
int thread_env_socket_uninit()
{
#ifndef WIN32
#else
// win
WSACleanup();
#endif
return 0;
}
bool safe_close_socket(SOCKET& sk)
{
bool b_rc = false;
try {
#ifndef WIN32
if ((int)INVALID_SOCKET != sk) {
::close(sk);
#else
if ((int)INVALID_SOCKET != sk) {
closesocket(sk);
#endif
}
b_rc = true;
} catch (...) {
b_rc = false;
}
sk = (int)INVALID_SOCKET;
return b_rc;
}
NS_SOCKET_EASY_END
接口的测试代码
// @file main.cpp
// @note
// set date on linux env : date -s "2017-10-29 12:08:00"
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <string.h>
#include "const_define.h"
#include "my_data_type.h"
#include "business_client.h"
#include "business_server.h"
void version();
void help();
int main(int argc, char** argv)
{
system("clear");
version();
NS_SOCKET_EASY::thread_env_socket_init();
do {
if (2 != argc) {
help();
break;
}
if (0 == strcmp(argv[1], CMD_PARAM_RUN_AS_CLIENT)) {
client_proc();
} else if (0 == strcmp(argv[1], CMD_PARAM_RUN_AS_SERVER)) {
server_proc();
} else {
help();
}
} while (0);
printf("%s\n", LINE80);
printf("THE END\n");
printf("%s\n", LINE80);
NS_SOCKET_EASY::thread_env_socket_uninit();
return 0;
}
void version()
{
printf("%s\n", LINE80);
printf("%s %s %s\n",
PROG_NAME,
PROG_VER,
PROG_MODIFY_TIME);
printf("%s\n", LINE80);
}
void help()
{
printf("%s\n", LINE80);
printf("usage:\n");
printf("%s %s\n",
PROG_NAME,
CMD_PARAM_RUN_AS_CLIENT);
printf("%s %s\n",
PROG_NAME,
CMD_PARAM_RUN_AS_SERVER);
printf("%s\n", LINE80);
}
// @file business_server.h
#ifndef __BUSINESS_SERVER_H__
#define __BUSINESS_SERVER_H__
#include "socket_tcp_server.h"
void server_proc();
#endif // #ifndef __BUSINESS_SERVER_H__
// @file business_client.h
#ifndef __BUSINESS_CLIENT_H__
#define __BUSINESS_CLIENT_H__
#include "socket_tcp_client.h"
void client_proc();
#endif // #ifndef __BUSINESS_CLIENT_H__
// @file business_server.cpp
#include <stdlib.h>
#include <stdio.h>
#include "business_server.h"
void server_proc()
{
int i_tmp = 0;
SOCKET i_client_fd = INVALID_SOCKET;
NS_SOCKET_EASY::socket_tcp_server server;
std::string str_client_ip = "";
std::string str_client_port = "";
char sz_buf[0x100] = {'\0'};
printf(">> server_proc\n");
do {
if (!server.listen_local_port(54321)) {
printf("server.listen_local_port failed : %s\n", server.get_last_error_string());
break;
}
i_client_fd = server.accept_client(str_client_ip, str_client_port);
if (INVALID_SOCKET == i_client_fd) {
break;
}
printf("client coming : %s : %s\n", str_client_ip.c_str(), str_client_port.c_str());
// recv
i_tmp = server.recv_until_over(i_client_fd, sz_buf, (int)sizeof(sz_buf));
if ((int)sizeof(sz_buf) != i_tmp) {
printf("server.recv_until_over failed : %s\n", server.get_last_error_string());
break;
} else {
printf("server.recv_until_over : %s\n", sz_buf);
}
// send
strcpy(sz_buf, "hello, i'm server");
i_tmp = server.send_until_over(i_client_fd, sz_buf, (int)sizeof(sz_buf));
if ((int)sizeof(sz_buf) != i_tmp) {
printf("server.send_until_over failed : %s\n", server.get_last_error_string());
break;
}
} while (0);
server.close_socket_handle(i_client_fd);
server.close_socket_handle();
printf("<< server_proc\n");
}
// @file business_client.cpp
#include <stdlib.h>
#include <stdio.h>
#include "business_client.h"
void client_proc()
{
bool b_rc = false;
int i_tmp = 0;
char sz_buf[0x100] = {'\0'};
NS_SOCKET_EASY::socket_tcp_client client;
printf(">> client_proc\n");
do {
// connect server port
if (!client.is_connect_ok()) {
printf("!client.is_connect_ok()\n");
b_rc = client.connect("127.0.0.1", 54321, 1);
printf("client.connect(\"127.0.0.1\", 54321, 1) = %s\n", b_rc ? "true" : "false");
if (!b_rc) {
printf("client.connect failed : %s\n", client.get_last_error_string());
break;
}
}
// send
strcpy(sz_buf, "hello, i'm client");
i_tmp = client.send_until_over(client.get_socket_handle(), sz_buf, (int)sizeof(sz_buf));
if ((int)sizeof(sz_buf) != i_tmp) {
printf("client.send_until_over failed : %s\n", client.get_last_error_string());
break;
}
// recv
i_tmp = client.recv_until_over(client.get_socket_handle(), sz_buf, (int)sizeof(sz_buf));
if ((int)sizeof(sz_buf) != i_tmp) {
printf("client.recv_until_over failed : %s\n", client.get_last_error_string());
break;
} else {
printf("client.recv_until_over : %s\n", sz_buf);
}
} while (0);
// close socket
client.close_socket_handle();
printf("<< client_proc\n");
}
// @file const_define.h
#ifndef _CONST_DEFINE_H_
#define _CONST_DEFINE_H_
#define PROG_NAME "tcp_socket_easy"
#define PROG_VER "1.0.0.1"
#define PROG_MODIFY_TIME "2017-12-5 21:31"
#define LINE80 "--------------------------------------------------------------------------------"
// client cmd line : tcp_socket_easy -client
// server cmd line : tcp_socket_easy -server
#define CMD_PARAM_RUN_AS_CLIENT "-client"
#define CMD_PARAM_RUN_AS_SERVER "-server"
#endif // #ifndef _CONST_DEFINE_H_
// @file my_data_type.h
#ifndef _MY_DATA_TYPE_H_
#define _MY_DATA_TYPE_H_
#ifndef NULL
#define NULL 0
#endif // #ifndef NULL
#define MAX_UL ((unsigned long)-1)
#endif // #ifndef _MY_DATA_TYPE_H_
工程配置文件
win版的工程是vs2010vc++的sln.
linux版是自己写的Makefile.
# ==============================================================================
# makefile
# lostspeed 2017-12-5
# note
# when first build on vmware's linux, please adjust date time for build project
# e.g. date -s "2017-12-5 21:49:00"
# ==============================================================================
BIN = tcp_socket_easy
LINE80 = --------------------------------------------------------------------------------
CC = g++ -std=c++98
CFLAGS = -Wall -g
INC = -I. -I./socket_easy
LIBS = -lstdc++ -pthread
LIBPATH = /usr/local/lib
DEPEND_CODE_DIR = ./empty_dir \
DEPEND_CODE_SRC = $(shell find $(DEPEND_CODE_DIR) -name '*.cpp')
DEPEND_CODE_OBJ = $(DEPEND_CODE_SRC:.cpp=.o)
# root code dir is ./'s code, e.g. main.cpp
ROOT_CODE_SRC = $(shell find ./ -name '*.cpp')
ROOT_CODE_OBJ = $(ROOT_CODE_SRC:.cpp=.o)
# if no sub code dir, must fill a sub dir exist but empty. e.g. ./empty_dir
# if have sub code dir, fill it like DEPEND_CODE_DIR
# e.g. ./xx_subdir/xx_type/
SUB_CODE_DIR = ./socket_easy
SUB_CODE_SRC = $(shell find $(SUB_CODE_DIR) -name '*.cpp')
SUB_CODE_OBJ = $(SUB_CODE_SRC:.cpp=.o)
help:
clear
@echo $(LINE80)
@echo "ROOT_CODE_SRC = " $(ROOT_CODE_SRC)
@echo "ROOT_CODE_OBJ = " $(ROOT_CODE_OBJ)
@echo "DEPEND_CODE_DIR = " $(DEPEND_CODE_DIR)
@echo "DEPEND_CODE_SRC = " $(DEPEND_CODE_SRC)
@echo "DEPEND_CODE_OBJ = " $(DEPEND_CODE_OBJ)
@echo "SUB_CODE_DIR = " $(SUB_CODE_DIR)
@echo "SUB_CODE_SRC = " $(SUB_CODE_SRC)
@echo "SUB_CODE_OBJ = " $(SUB_CODE_OBJ)
@echo "INC = " $(INC)
clean:
clear
@echo $(LINE80)
@echo make clean
rm -f $(BIN) $(ROOT_CODE_OBJ) $(DEPEND_CODE_OBJ) $(SUB_CODE_OBJ)
all:$(BIN)
@echo $(LINE80)
@echo make all
chmod 777 $(BIN)
find . -name $(BIN)
$(BIN) : $(ROOT_CODE_OBJ) $(DEPEND_CODE_OBJ) $(SUB_CODE_OBJ)
$(CC) $(CFLAGS) -o $@ $^
.cpp.o:
$(CC) -c $(CFLAGS) $^ -o $@ $(INC) -L$(LIBPATH) $(LIBS)
rebuild:
make clean
@echo $(LINE80)
make all
rebuild_and_run:
make rebuild
@echo $(LINE80)
./$(BIN)
总结
如果有好用的封装,我是不可能封装的, 太懒了。
只有不能忍或必须要动手的情况,才会自己封装。
但是封装也挺占用时间的,这个封装类+测试代码,整了2次,用了9小时(7+2).
以后,如果是tcp的socket操作,我就用自己的封装类,看着用着都舒服 :)