接口类的实现(抽象类)
_public_socket.h
该头文件用于包含所有该系统平台socket所需要依赖的库。
#ifndef MY_TINY_STL__PUBLIC_SOCKET_H
#define MY_TINY_STL__PUBLIC_SOCKET_H
#include <winsock2.h>
#pragma comment (lib, "ws2_32.lib")
#endif
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
TCP_INTERFACE.h(作用于win平台)
由于该接口由服务器端和客户端继承,而两者同样的函数成员也就是这些了,设计客户端和服务器端时就只需要考虑各自的套接字以及其余操作的成员函数,也不需要管理DLL的开关。
#ifndef MY_TINY_STL_TCP_INTERFACE_H
#define MY_TINY_STL_TCP_INTERFACE_H
#include "_public_socket.h"
class TCP_INTERFACE {
public:
TCP_INTERFACE(){
WSADATA wsaData;
WSAStartup( MAKEWORD(2, 2), &wsaData);
}
virtual int Send(const void*buf,const int buflen) = 0;
virtual int Recv(void*buf,const int buflen) = 0;
virtual bool Close() = 0;
~TCP_INTERFACE(){
WSACleanup();
}
};
#endif
服务器端封装
TCP_SOCKET_SERVER.h
#ifndef MY_TINY_STL_TCP_SOCKET_SERVER_H
#define MY_TINY_STL_TCP_SOCKET_SERVER_H
#include "TCP_INTERFACE.h"
class TCP_SOCKET_SERVER: public TCP_INTERFACE{
public:
TCP_SOCKET_SERVER();
~TCP_SOCKET_SERVER();
bool Bind(int port);
bool Listen();
bool Accept();
int Send(const void*buf,const int buflen);
int Recv(void* buf,const int buflen);
bool Close();
private:
SOCKET servSock;
SOCKET clntSock;
sockaddr_in sockAddr;
};
#endif
TCP_SOCKET_SERVER.cpp
#include "TCP_SOCKET_SERVER.h"
TCP_SOCKET_SERVER::TCP_SOCKET_SERVER(): servSock(0), clntSock(0) {
memset(&sockAddr, 0, sizeof(sockAddr));
}
TCP_SOCKET_SERVER::~TCP_SOCKET_SERVER() {
if(clntSock!=0)closesocket(clntSock);
if(servSock!=0)closesocket(servSock);
}
bool TCP_SOCKET_SERVER::Bind(int port) {
servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
sockAddr.sin_family = PF_INET;
sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
sockAddr.sin_port = htons(port);
if(bind(servSock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR))!=0){
closesocket(servSock);
servSock = 0;
return false;
}
return true;
}
bool TCP_SOCKET_SERVER::Listen() {
if(servSock==0)
return false;
if(listen(servSock,20)!=0){
closesocket(servSock);
servSock = 0;
return false;
}
return true;
}
bool TCP_SOCKET_SERVER::Accept() {
SOCKADDR t;int nSize = sizeof(SOCKADDR);
clntSock = accept(servSock,&t,&nSize);
if(clntSock<=0){clntSock=0; return false};
return true;
}
int TCP_SOCKET_SERVER::Send(const void *buf, const int buflen) {
return send(clntSock,(const char*)buf,buflen,0);
}
int TCP_SOCKET_SERVER::Recv(void *buf, const int buflen) {
return recv(clntSock,(char*)buf,buflen,0);
}
bool TCP_SOCKET_SERVER::Close() {
if(clntSock==0)
return false;
if( closesocket(clntSock)!=0){
return false;
}clntSock = 0;
return true;
}
客户端的封装
TCP_SOCKET_CLIENT.h
增加了利用域名查询ip地址的成员函数gethostbyname(),挺好玩的!
#ifndef PRACTICE_TCP_SOCKET_CLIENT_H
#define PRACTICE_TCP_SOCKET_CLIENT_H
#include "TCP_INTERFACE.h"
#include <iostream>
class TCP_SOCKET_CLIENT: public TCP_INTERFACE {
public:
TCP_SOCKET_CLIENT();
~TCP_SOCKET_CLIENT();
bool Connect(const char* IPAdrr,u_short port);
void Gethostbyname(const char*URL);
int Send(const void* buf,const int bufSize);
int Recv(void* buf,const int bufSize);
bool Close();
private:
SOCKET clntSock;
sockaddr_in sockAddr;
};
#endif
TCP_SOCKET_CLIENT.cpp
#include "TCP_SOCKET_CLIENT.h"
TCP_SOCKET_CLIENT::TCP_SOCKET_CLIENT():clntSock(0) {
memset(&sockAddr,0,sizeof sockAddr);
}
bool TCP_SOCKET_CLIENT::Close() {
if(clntSock==0)
return false;
if(closesocket(clntSock)!=0)
return false;
clntSock = 0;
return true;
}
bool TCP_SOCKET_CLIENT::Connect(const char *IPAdrr, u_short port) {
clntSock = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
sockAddr.sin_family = PF_INET;
sockAddr.sin_addr.s_addr = inet_addr(IPAdrr);
sockAddr.sin_port = htons(port);
if(connect(clntSock,(SOCKADDR*)&sockAddr,sizeof(sockAddr))!=0){
closesocket(clntSock);
clntSock = 0;
return false;
}
return true;
}
int TCP_SOCKET_CLIENT::Send(const void *buf, const int bufSize) {
return send(clntSock,(const char*)buf,bufSize,0);
}
int TCP_SOCKET_CLIENT::Recv(void *buf, const int bufSize) {
return recv(clntSock,(char*)buf,bufSize,0);
}
void TCP_SOCKET_CLIENT::Gethostbyname(const char* URL) {
hostent *host = gethostbyname(URL);
if(!host){
std::cout<<"Get IP address error!\n";
return;
}
std::cout<<URL<<std::endl;
for(int i=0; host->h_aliases[i]; i++){
printf("Aliases %d: %s\n", i+1, host->h_aliases[i]);
}
printf("Address type: %s\n", (host->h_addrtype==AF_INET) ? "AF_INET": "AF_INET6");
for(int i=0; host->h_addr_list[i]; i++){
printf("IP addr %d: %s\n", i+1, inet_ntoa( *(struct in_addr*)host->h_addr_list[i] ) );
}
}
TCP_SOCKET_CLIENT::~TCP_SOCKET_CLIENT() {
if(clntSock!=0)
closesocket(clntSock);
}
实例一:回声程序通信
服务器回声程序
绑定本地1234端口,进入监听状态等待请求,如果通信对象关闭了通信,也不慌,重新goto到等待请求得到新的通信套接字
#include <iostream>
#include "TCP_SOCKET_SERVER.h"
#define BUF_SIZE 1000
using namespace std;
int main() {
TCP_SOCKET_SERVER a;
a.Bind(1234);
a.Listen();
restart:
a.Accept();
while (1) {
char *x = new char[BUF_SIZE];
memset(x, 0, BUF_SIZE);
int size = a.Recv(x, BUF_SIZE);
if (size <= 0)
break;
if (a.Send(x, size) <= 0)
break;
}
cout << "connect is over.Waiting for a new connection!\n";
goto restart;
}
客户端通信程序
为保持持续通信,一旦客户端拒绝了请求,那么弹出循环重新连接,并设置连接超时操作。
#include "TCP_SOCKET_CLIENT.h"
#define BUF_SIZE 100
int main(){
TCP_SOCKET_CLIENT t;
const char* to = "127.0.0.1";
restart:
if(!t.Connect(to,1234)){
std::cout<<"connected timeout!";
return 0;
}
while(1){
std::cout<<"\nInput your message:\n";
char buf[BUF_SIZE] = {0};
std::cin.getline(buf,99);
int size = t.Send(buf,BUF_SIZE);
if(size<=0)
break;
memset(buf,0,sizeof buf);
if(t.Recv(buf,size)<=0)
break;
printf("received from %s is:\n",to);
std::cout<<buf;
}
std::cout<<"The Server is disconnected,and socket has been cleaned up,socket connection has been re-established\n";
goto restart;
return 0;
}
回声效果
客户端收到的结果
服务器端一直运行着,只要不关闭,但每次只能和一个客户端进行通信,通信完后重新等待连接。
实例二:文件操作,传送图片(掌握重复传包)
分析待传图片
看看这百万大小的字节,一次肯定是传不完的,所以我们需要发送端不断的续传,直到传送完毕。
发送端程序
#include "TCP_SOCKET_CLIENT.h"
#include <fstream>
int main(){
TCP_SOCKET_CLIENT t;
const char* to = "127.0.0.1";
restart:
if(!t.Connect(to,1234)){
std::cout<<"connected timeout!";
return 0;
}
std::ifstream img("D:/DesktopBackground/L-69.png",std::ios::in|std::ios::binary);
img.seekg(0,std::ios::end);
int len = img.tellg();
img.seekg(0,std::ios::beg);
if(len>0){printf("read OK\n");}
else {printf("file is empty!");return 0;}
char * buf = new char[len];
img.read(buf,len);
int sum = 0;
while(sum<len){
int sendlen = t.Send(buf,len);
if(sendlen<=0){
printf("Send Erro!");
return 0;
}
sum += sendlen;
}
printf("Send OK!");
return 0;
}
接收端程序
#include <iostream>
#include "TCP_SOCKET_SERVER.h"
#include <fstream>
#define BUF_SIZE 100
using namespace std;
int main() {
TCP_SOCKET_SERVER a;
a.Bind(1234);
a.Listen();
a.Accept();
ofstream t("test.png",ios::binary|ios::out);
while(1){
char buf[BUF_SIZE];
int sz = a.Recv(buf,BUF_SIZE);
if(sz<=0){
cout<<"Finish !";
return 0;
}
t.seekp(0,ios::end);
t.write(buf,sz);
}
}
接收结果
一模一样毫无偏差
|