现在我们要开始进行客户端的编码了。
如下客户端代码:
#include "XTcp.h"
int main()
{
XTcp client; //client创建之后要建立连接,第一步客户端和服务器都是一样的,
//区别是第二步,客户端有需要connect去连接服务器有一个三次握手的过程
client.Connect("192.168.16.223", 8081);
client.Send("clientyesyesyes", 20);
char buffer[1024] = { 0 };
client.Recv(buffer,sizeof(buffer));
printf("%sn", buffer);
return 0;
}
分析上面的代码,三次握手在客户端Connect之后,服务器accept时就已经完成。三次握手流程如下图。
通用流程代码XTcp.cpp
#include "XTcp.h" #ifdef WIN32 #include#define socklen_t int #else #include #include #include #include #define closesocket close #endif #include #include #include #include using namespace std; XTcp::XTcp() { #ifdef WIN32 static bool first = true; if (first) { first = false; //保证只进入一次 WSADATA ws; WSAStartup(MAKEWORd(2, 2), &ws); //相当于加载了动态库,给引用增加1,这个只需要调用以此,但是需要调用在最前面 } #endif } int XTcp::CreateSocket() //第一步创建socket { sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == -1) { printf("create socket failed!n"); } return sock; } bool XTcp::Bind(unsigned short port) { if (sock <= 0) CreateSocket(); //创建 sockaddr_in saddr; saddr.sin_family = AF_INET; //协议 saddr.sin_port = htons(port); //本地字节序转换为网络字节序 saddr.sin_addr.s_addr = htonl(0); //任意ip地址发过来的数据都接收 //绑定 //用bind绑定,绑定哪一个端口 if (::bind(sock, (sockaddr*)&saddr, sizeof(saddr)) != 0) { printf("bind port %d failed!n", port); return false; } printf("bind port %d success!n", port); listen(sock, 10); //这个函数已经调用,就会告诉系统,这个socket可以通过这 //个端口来跟它进行接收连接了 //但是,连接的信息还会用到另外一个函数。10指的是在我这次获取连接信息的时候 //最大支持多少个连接信息 return true; } int XTcp::Recv(char* buf, int bufsize) { //Revc考虑一点,有时候需要接收指定大小,接收不到指定大小,就会失败 return recv(sock, buf, bufsize, 0); } int XTcp::Send(const char* buf, int size) { int s = 0; while(s!=size) //一直发送,直到发送完毕 { int len = send(sock, buf + s, size - s, 0); if (len <= 0) break; s += len; } return s; } void XTcp::Close() { if (sock <= 0) return; closesocket(sock); } XTcp XTcp::Accept() { XTcp tcp; sockaddr_in caddr; socklen_t len = sizeof(caddr); int client = accept(sock, (sockaddr*)&caddr, &len);//创建一个新的socket,用来与客户端单独进行通信 if (client <= 0) return tcp; //如何让外部知道我accept是成功还是失败,可以通过这个返回对象的默认socket来判断 printf("accept client %dn", client); tcp.ip = inet_ntoa(caddr.sin_addr); tcp.port = ntohs(caddr.sin_port); //将网络字节序转化为本地字节序 tcp.sock = client; printf("client ip is %s,port is %dn", tcp.ip.c_str(), tcp.port); return tcp; } bool XTcp::Connect(const char* ip, unsigned short port) { if (sock <= 0) CreateSocket(); sockaddr_in saddr; saddr.sin_family = AF_INET; saddr.sin_port = htons(port); //本地字节序转换为网络字节序 saddr.sin_addr.s_addr = inet_addr(ip); //将字符串类型转化为整数类型的ip地址 if (connect(sock, (sockaddr*)&saddr, sizeof(saddr)) != 0) { printf("connect %s:%d failed:%sn", ip, port, strerror(errno)); return false; } printf("connect %s:%d success!n", ip, port); return true; } XTcp::~XTcp() { }
XTcp.h
//#pragma once #ifndef _XTCP_H_ #define _XTPC_H_ #includeclass XTcp { public: int CreateSocket(); bool Bind(unsigned short port); XTcp Accept(); //注意这个返回类型不是指针类型,我们需要在后面重新调用一个closesocket函数 void Close(); int Recv(char *buf,int bufsize); int Send(const char *buf,int sendsize); bool Connect(const char *ip,unsigned short port); //注意,暂时不考虑连接超时的情况 XTcp(); virtual ~XTcp(); int sock = 0; unsigned short port = 0; std::string ip; //这些信息可以对外开放 }; #endif //_XTCH_H_



