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开启了两个客户端进行连接:

 

 

 

 

 

 



 

posted @ 2020-08-01 15:10  sunshine_gzw  阅读(305)  评论(0编辑  收藏  举报