C语言实现tcp客户端和tcp服务端,Qt调用测试

目录

  • tcp客户端
  • tcp服务端

C语音实现tcp客户端和tcp服务端,并用Qt调用测试,支持windows和linux跨平台

tcp客户端

创建tcp客户端,在子线程轮询接收数据,接收到的数据通过回调函数传递给mainwindow主线程处理,界面按钮发送tcp数据。

pro工程文件添加

win32{
LIBS += -lws2_32}

tcpclient.h

#ifndef TCPCLIENT_H
#define TCPCLIENT_H

#include 
#include 

#ifdef _WIN32
#include 
#include 
#define socklen_t int
#else
#include 
#include 
#include 
#endif

typedef struct {
    int32_t fd;
    int32_t localPort;
    int32_t remotePort;
    int32_t isStart;
    int32_t isLoop;
    int32_t notRemoteInit;
    pthread_t threadId;
    int isServer;//0客户端,1服务端

    //char serverIp[30];
    void* user;
    struct sockaddr_in local_addr;
    struct sockaddr_in remote_addr;
    void (*receive)(char *data, int32_t nb_data,void* user);
}TcpHandle;

#ifdef __cplusplus
extern "C"{
#endif
int32_t create_tcpClient(TcpHandle* tcpClient,char* serverIp,int32_t serverPort,int32_t plocalPort);
void start_tcpClient(TcpHandle* tcpClient);
void destroy_tcpClient(TcpHandle* tcpClient);
void stop_tcpClient(TcpHandle* tcpClient);
int32_t sendData_tcpClient(TcpHandle* tcpClient, char* data, int32_t len);
#ifdef __cplusplus
}
#endif

#endif // TCPCLIENT_H

tcpclient.c

#include "tcpclient.h"

/**
 * @brief create_tcpClient
 * @param tcpClient 句柄
 * @param serverIp 服务端IP
 * @param serverPort
 * @param plocalPort
 * @return
 */
int32_t create_tcpClient(TcpHandle *tcpClient, char *serverIp, int32_t serverPort, int32_t plocalPort)
{
    if (tcpClient == NULL)		return -1;
    tcpClient->isServer = 0;

    tcpClient->localPort = plocalPort;
    tcpClient->fd = -1;
    tcpClient->remotePort = serverPort;

#ifdef _WIN32
    WORD wVersionRequested;
    WSADATA wsaData;
    wVersionRequested = MAKEWORD(2, 2);
    WSAStartup(wVersionRequested, &wsaData);//初始化socket库
#endif

    tcpClient->local_addr.sin_family = AF_INET;
    tcpClient->local_addr.sin_port = htons(tcpClient->localPort);
    // lcl_addr.sin_addr.s_addr=inet_addr(ip);
    tcpClient->local_addr.sin_addr.s_addr = INADDR_ANY;
    if((tcpClient->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)//客户端只需要一个套接字文件描述符,用于和服务器通信
    {
        perror("socket");
        return -2;
    }

    tcpClient->remote_addr.sin_family = AF_INET;
    tcpClient->remote_addr.sin_port = htons(tcpClient->remotePort);
    tcpClient->notRemoteInit=serverPort>0?0:1;

#ifdef _WIN32
    tcpClient->remote_addr.sin_addr.S_un.S_addr=inet_addr(serverIp);
#else
    tcpClient->remote_addr.sin_addr.s_addr = inet_addr(serverIp);//将点分十进制IP转换成网络字节序IP
#endif

    if(connect(tcpClient->fd, (struct sockaddr *)&tcpClient->remote_addr, sizeof(tcpClient->remote_addr)) < 0)
    {
        perror("connect");
        return -3;
    }

    return 0;
}

void* recv_thread_tcpClient(void *obj) {
#ifdef _WIN32
    WORD wVersionRequested;
    WSADATA wsaData;
    wVersionRequested = MAKEWORD(2, 2);
    WSAStartup(wVersionRequested, &wsaData);
#endif
    TcpHandle *ptcpClient = (TcpHandle*) obj;
    ptcpClient->isStart = 1;
#ifdef _WIN32
    int32_t timeout=200;
    setsockopt(ptcpClient->fd, SOL_SOCKET, SO_RCVTIMEO, (const char*) &timeout,  sizeof(timeout));
#else
    struct timeval tv;
    tv.tv_sec = 0;
    tv.tv_usec = 20000;  // 20 ms
    setsockopt(ptcpClient->fd, SOL_SOCKET, SO_RCVTIMEO, (const char*) &tv,	sizeof(struct timeval));
#endif
    char buffer[2048] = { 0 };
    ptcpClient->isLoop = 1;

    int32_t len = 0;
    socklen_t src_len = sizeof(struct sockaddr_in);

    while (ptcpClient->isLoop)
    {
        struct sockaddr_in src;
        memset(&src, 0, src_len);
        memset(buffer, 0, 2048);
        if ((len = recvfrom(ptcpClient->fd, buffer, 2048, 0,	(struct sockaddr*) &src, &src_len)) > 0)
        {
            if(ptcpClient->notRemoteInit)
            {
                ptcpClient->remotePort = ntohs(src.sin_port);
                ptcpClient->remote_addr.sin_port = src.sin_port;//htons(udp->remotePort);

#ifdef _WIN32
                ptcpClient->remote_addr.sin_addr.S_un.S_addr=src.sin_addr.S_un.S_addr;
#else
                ptcpClient->remote_addr.sin_addr.s_addr = src.sin_addr.s_addr;
#endif

                ptcpClient->notRemoteInit=0;
            }
            if (ptcpClient->receive)	ptcpClient->receive(buffer, len, ptcpClient->user);
        }
    }
    ptcpClient->isStart = 0;
    #ifdef _WIN32
    closesocket(ptcpClient->fd);
    #else
    close(ptcpClient->fd);
    #endif
    ptcpClient->fd = -1;

    return NULL;
}

void start_tcpClient(TcpHandle *tcpClient)
{
    if (tcpClient == NULL)	return;
    if (pthread_create(&tcpClient->threadId, 0, recv_thread_tcpClient, tcpClient)) {
        printf("could not start thread\n");
    }
}

void stop_tcpClient(TcpHandle *tcpClient)
{
    if (tcpClient == NULL)	return;
    tcpClient->isLoop = 0;
    while (tcpClient->isStart)
        usleep(1000);
}

void destroy_tcpClient(TcpHandle *tcpClient)
{
    if (tcpClient == NULL)
        return;
    stop_tcpClient(tcpClient);
    if (tcpClient->fd > 0)
    {
#ifdef _WIN32
        closesocket(tcpClient->fd);
#else
        close(tcpClient->fd);
#endif
        tcpClient->fd = -1;
    }
}

int32_t sendData_tcpClient(TcpHandle *tcpClient, char *data, int32_t len)
{
    if (tcpClient == NULL || !tcpClient->isStart || tcpClient->notRemoteInit || data==NULL)	return -1;
    return sendto(tcpClient->fd, data, len, 0, (struct sockaddr*) &tcpClient->remote_addr,sizeof(struct sockaddr));
}

QT调用示例

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include 
#include 

void g_receive(char *data, int32_t nb_data,void *user)
{
    if (user == NULL || nb_data <= 0)
        return;
    MainWindow *mw = (MainWindow*) user;
    std::string tmpstr(data,nb_data);
    mw->recvTcpData(tmpstr);
    return;
}

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    pTcpHandle = (TcpHandle *)malloc(sizeof(TcpHandle));
    pTcpHandle->receive = g_receive;
    pTcpHandle->user = this;
    create_tcpClient(pTcpHandle,"192.168.72.35",60000,0);
    start_tcpClient(pTcpHandle);
}

MainWindow::~MainWindow()
{
    destroy_tcpClient(pTcpHandle);
    QThread::msleep(20);
    if(pTcpHandle) free(pTcpHandle);
    delete ui;
}

void MainWindow::recvTcpData(std::string str)
{
    qDebug()<<"["<<__FILE__<<"]"<<__LINE__<<__FUNCTION__<<"recv data:"<<QString::fromStdString(str);
}

void MainWindow::on_pushButton_clicked()
{
    int ret = sendData_tcpClient(pTcpHandle,ui->lineEdit->text().toUtf8().data(),ui->lineEdit->text().size());
    qDebug()<<"["<<__FILE__<<"]"<<__LINE__<<__FUNCTION__<<"send data:"<<ret;
}

tcp服务端

创建tcp服务端,在子线程监听,当有客户端连接时,再启动一个子线程负责与该客户端进行数据收发,接收到的数据通过回调函数传递给mainwindow主线程处理,本例是回复一条confirm消息;支持多个客户端同时连接到tcp服务端,与每个客户端的通信是在独立的线程完成。
pro工程文件添加

win32{
LIBS += -lws2_32}

tcpserver.h

#ifndef TCPSERVER_H
#define TCPSERVER_H

#include 
#include 

#ifdef _WIN32
#define _WIN32_WINNT 0x0600
#include "windows.h"
#include 
#include 

#define socklen_t int
#else
#include 
#include 
#include 
#include 
#endif

typedef struct {
    int32_t serverfd;
    int32_t connFd;
    //int32_t lclPort;
    int32_t isStart;
    int32_t isLoop;
    pthread_t threadId;
    int32_t serverPort;
    void* user;
    char remoteIp[32];

    struct sockaddr_in local_addr;
    struct sockaddr_in remote_addr;
    void (*receive)(char *data, int32_t nb_data,void* user,int32_t clientFd);
    void (*startStunTimer)(void* user);
}TcpServer;

#ifdef __cplusplus
extern "C"{
#endif
int32_t create_tcpServer(TcpServer* tcpServer,int32_t listenPort);
void destroy_tcpServer(TcpServer* tcpServer);
void start_tcpServer(TcpServer* tcpServer);
void stop_tcpServer(TcpServer* tcpServer);
int32_t sendData_tcpServer(TcpServer* tcpServer, char* data, int32_t len, int32_t clientFd);
#ifdef __cplusplus
}
#endif

#endif // TCPSERVER_H

tcpserver.c

#include "tcpserver.h"

#ifndef _WIN32
#include 
#define GetSockError()	errno
#define SetSockError(e)	errno = e

#define closesocket(s)	close(s)
#else
#define GetSockError()	WSAGetLastError()
#define SetSockError(e)	WSASetLastError(e)
#define setsockopt(a,b,c,d,e)	(setsockopt)(a,b,c,(const char *)d,(int)e)

#endif

int32_t create_tcpServer(TcpServer *tcpServer, int32_t listenPort)
{
    if (tcpServer == NULL)
        return 1;

    tcpServer->serverfd = -1;
    tcpServer->serverPort = listenPort;
    tcpServer->local_addr.sin_family = AF_INET;
    tcpServer->local_addr.sin_port = htons(listenPort);
#ifdef _WIN32
    tcpServer->local_addr.sin_addr.S_un.S_addr=INADDR_ANY;
#else
    tcpServer->local_addr.sin_addr.s_addr = INADDR_ANY;
#endif
    return 0;
}

void* run_tcpConnClient_thread(void *obj)
{
    TcpServer* tcpServer=(TcpServer*)obj;
    int connfd=tcpServer->connFd;
    char remoteIp[32]={0};
    strcpy(remoteIp,tcpServer->remoteIp);

    int32_t nBytes =0;
    char buffer[2048] = { 0 };
    while (tcpServer->isLoop)
    {
        memset(buffer, 0, 2048);
        nBytes = recv(connfd, buffer, 2048, 0);

        if (nBytes > 0)
        {
            tcpServer->receive(buffer, nBytes, tcpServer->user,connfd);
        }
        else if (nBytes == -1)
        {
            int32_t sockerr = GetSockError();
            if (sockerr == EINTR)
                continue;
            if (sockerr == EWOULDBLOCK || sockerr == EAGAIN)
            {
                nBytes = 0;
                continue;
            }
#ifdef Q_OS_LINUX
            printf("%s, recv returned %d. GetSockError(): %d (%s)\n",  __FUNCTION__, nBytes, sockerr, strerror(sockerr));
#endif

            continue;
        }
    }
    closesocket(connfd);

    return NULL;
}

void* run_tcpServer_thread(void *obj) {
#ifdef _WIN32
    WORD wVersionRequested;
    WSADATA wsaData;
    wVersionRequested = MAKEWORD(2, 2);
    WSAStartup(wVersionRequested, &wsaData);
#endif
    TcpServer *tcpServer = (TcpServer*) obj;
    tcpServer->isStart = 1;
    tcpServer->serverfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
#ifdef _WIN32
    int32_t timeout=200;
    setsockopt(tcpServer->serverfd, SOL_SOCKET, SO_RCVTIMEO, (const char*) &timeout,  sizeof(timeout));
#else
    struct timeval tv;
    tv.tv_sec = 0;
    tv.tv_usec = 200000;  // 200 ms
    setsockopt(tcpServer->serverfd, SOL_SOCKET, SO_RCVTIMEO, (const char*) &tv,
            sizeof(struct timeval));
#endif
    printf("\nhttp tcp server is starting,listenPort==%d", tcpServer->serverPort);

    if (bind(tcpServer->serverfd, (struct sockaddr*) &tcpServer->local_addr,sizeof(struct sockaddr_in)) < 0) {
        printf("http server bind error(%d)",GetSockError());
        exit(1);
    }
    listen(tcpServer->serverfd, 5);

    tcpServer->isLoop = 1;
    socklen_t src_len = sizeof(struct sockaddr_in);
    while (tcpServer->isLoop)
    {
        struct sockaddr_in src;
        memset(&src, 0, src_len);
        int connfd = accept(tcpServer->serverfd, (struct sockaddr*) &src, &src_len);
        if(connfd>-1)
        {
            pthread_t th;
            tcpServer->connFd=connfd;
            memset(tcpServer->remoteIp,0,sizeof(tcpServer->remoteIp));
#ifdef _WIN32
            inet_ntop(AF_INET,&src.sin_addr.s_addr, tcpServer->remoteIp, sizeof(tcpServer->remoteIp));
#else
            inet_ntop(AF_INET,&src.sin_addr.s_addr, tcpServer->remoteIp, sizeof(tcpServer->remoteIp));
#endif

            pthread_create(&th, 0, run_tcpConnClient_thread, tcpServer);
        }
    }
    tcpServer->isStart = 0;
#ifdef _WIN32
        closesocket(tcpServer->serverfd);
#else
        close(tcpServer->serverfd);
#endif
    tcpServer->serverfd = -1;

    return NULL;
}

void start_tcpServer(TcpServer *tcpServer)
{
    if (tcpServer == NULL)	return;
    if (pthread_create(&tcpServer->threadId, 0, run_tcpServer_thread, tcpServer))
    {
        printf("::start could not start thread");
    }
}

void destroy_tcpServer(TcpServer *tcpServer)
{
    if (tcpServer == NULL)
        return;
    stop_tcpServer(tcpServer);
    if (tcpServer->serverfd > 0) {
        closesocket(tcpServer->serverfd);
        tcpServer->serverfd = -1;
    }
}

void stop_tcpServer(TcpServer *tcpServer)
{
    if (tcpServer == NULL)
        return;
    tcpServer->isLoop = 0;
    if(tcpServer->serverfd>0)    closesocket(tcpServer->serverfd);
    while (tcpServer->isStart)
        usleep(1000);
}

int32_t sendData_tcpServer(TcpServer *tcpServer, char *data, int32_t len,int32_t clientFd)
{
    if (tcpServer == NULL || !tcpServer->isStart || data==NULL)	return -1;
    int nBytes = send(clientFd, data, len, 0);

    return nBytes;
}

QT调用示例

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include 
#include 

void g_receive(char *data, int32_t nb_data,void *user,int32_t clientFd) {
    if (user == NULL)	return;
    MainWindow *mw = (MainWindow*) user;
    std::string tmpstr(data,nb_data);
    mw->recvTcpClientData(tmpstr,clientFd);
    printf("clientFd=%d\n",clientFd);
    return;
}

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    pTcpServer = (TcpServer *)malloc(sizeof(TcpServer));
    pTcpServer->receive = g_receive;
    pTcpServer->user = this;
    create_tcpServer(pTcpServer,9000);
    start_tcpServer(pTcpServer);
}

MainWindow::~MainWindow()
{
    destroy_tcpServer(pTcpServer);
    QThread::msleep(200);
    if(pTcpServer) free(pTcpServer);
    delete ui;
}

void MainWindow::recvTcpClientData(std::string str,int32_t clientFd)
{
    QString revMsg = QString::fromStdString(str);
    qDebug()<<"["<<__FILE__<<"]"<<__LINE__<<__FUNCTION__<<" "<<revMsg;

    QString sendMsg = revMsg + "RecvComfirm";
    sendData_tcpServer(pTcpServer,sendMsg.toUtf8().data(),sendMsg.size(),clientFd);
}


你可能感兴趣的:(C/C++,c语言,tcp/ip,qt)