socket编程(TCP)
由于服务端和和客户端有的代码是共用的,为了提高编译速度,所以用一个文件socketdll保存共享文件,生成动态链接库,以便调用。
socketdll文件含有:
XTcp.h:
#ifndef __XTCP__H__ #define __XTCP__H__ #ifdef WIN32 #ifdef SOCKETDLL_EXPORTS #define SOCKETDLL_API __declspec(dllexport) #else #define SOCKETDLL_API __declspec(dllimport) #endif #else #define SOCKETDLL_API #endif class SOCKETDLL_API XTcp { public: XTcp(); virtual ~XTcp(); int CreateSocket(); bool Bind(unsigned short port); bool Connect(const char* ip,unsigned short port); XTcp Accept(); int Recv(char *buf,int bufsize); int Send(const char* buf,int sendsize); void Close(); int sock = 0; unsigned short port = 0; char *ip; }; #endif
XTcp.cpp
#include "XTcp.h" #include<string.h> #include<stdio.h> #ifdef WIN32 #include<windows.h> #define socklen_t int #else #include<unistd.h> #include<sys/socket.h> #include<sys/types.h> #include<arpa/inet.h> #define closesocket close #endif XTcp::XTcp() { #ifdef WIN32 static int first = true; if (first) { first = false; WSADATA ws; WSAStartup(MAKEWORD(2,2),&ws); } #endif } //创建socket int XTcp::CreateSocket() { sock = socket(AF_INET,SOCK_STREAM,0); if (sock <= 0) { printf("创建socket失败!\n"); return sock; } printf("创建socket成功!sock=%d\n",sock); return sock; } bool XTcp::Bind(unsigned short port) { if (sock <= 0) CreateSocket(); sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(0); addr.sin_port = htons(port); if (::bind(sock, (sockaddr*)&addr, sizeof(addr)) != 0) { printf("绑定失败!\n"); return false; } printf("绑定成功! port=%d\n",port); printf("开始监听...\n"); listen(sock,20); return true; } //accept的行为是被动的 XTcp XTcp::Accept() { XTcp xtcp; sockaddr_in addr; socklen_t len = sizeof(addr); int client = accept(sock, (sockaddr*)&addr, &len); if (client <= 0) { return xtcp; } xtcp.sock = client; xtcp.ip = inet_ntoa(addr.sin_addr); xtcp.port = ntohs(addr.sin_port); printf("ip:%s %d\n",xtcp.ip,xtcp.port); return xtcp; } int XTcp::Recv(char *buf, int bufsize) { return recv(sock,buf,bufsize,0); } int XTcp::Send(const char* buf, int sendsize) { int x = 0; while (x != sendsize) { int len = send(sock,buf+x,sendsize-x,0); x += len; } return x; } void XTcp::Close() { if (sock <= 0) { closesocket(sock); } } bool XTcp::Connect(const char* ip, unsigned short port) { if (sock <= 0) CreateSocket(); sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(ip); if (connect(sock, (sockaddr*)&addr, sizeof(addr)) != 0) { printf("connect:%s %d,failed:%s\n",ip,port,strerror(sock)); return false; } printf("connect:%s %d success!\n", ip, port); return true; } XTcp::~XTcp() { }
makefile:
libsocketdll.so:XTcp.cpp XTcp.h g++ $+ -o $@ -fpic -shared -std=c++11 cp *.so /usr/lib/
makefile结构解释:
libsocketdll.so lib动态库的名字.so
-fpic:该参数表示去共享库寻找时不受地址改变而改变,也就是要用到该共享库,回到固定的地方寻找。
后面的操作还是找不到以来的库,所以把生成的依赖库复制到系统中去。
ok。现在共享库完成。
接下来看服务器端:
tcpserver文件:
tcpserver.cpp:
#include "XTcp.h" #include<string.h> #include<stdlib.h> #include<thread> class XTcpThread { public: XTcp client; void Main() { char buf[1024] = {0}; for (;;) { int x = client.Recv(buf,sizeof(buf)-1); if (x <= 0) break; buf[x] = '\0'; if (strstr(buf, "quit") != NULL) { char re[] = "quit success!\n"; client.Send(re,strlen(re)+1); break; } int sendlen = client.Send("ok!\n",4); printf("%s\n",buf); break; } client.Close(); delete this; } }; int main(int argc,char* argv[]) { unsigned short port = 8080; if (argc > 1) { port = atoi(argv[1]); } XTcp x; x.CreateSocket(); x.Bind(port); for (;;) { XTcp client = x.Accept(); XTcpThread* a = new XTcpThread(); a->client = client; std::thread th(&XTcpThread::Main,a); th.detach(); } x.Close(); while (1); return 0; }
makefile文件:
server:tcpserver.cpp g++ $+ -o $@ -I../socketdll -std=c++11 -lpthread -lsocketdll -L../socketdll
头文件的位置 依赖库的名字 依赖库所在位置
接下来是客户端:
tcpclient文件:
tcpclient.cpp:
#include "XTcp.h" int main() { XTcp client; client.Connect("192.168.213.133",4000); return 0; }
makefile文件:
tcpclient:main.cpp g++ $+ -o $@ -I../socketdll -std=c++11 -lpthread -lsocketdll -L../socketdll
目录结构:
tcpserver文件
tcpclient文件
socketdll文件
最终效果:
linux开启服务端:
SecureCRT开启了两个客户端进行连接: