当前位置:网站首页>C语音实现tcp客户端和tcp服务端,Qt调用测试
C语音实现tcp客户端和tcp服务端,Qt调用测试
2022-07-22 21:28:00 【架相】
C语音实现tcp客户端和tcp服务端,并用Qt调用测试,支持windows和linux跨平台
tcp客户端
创建tcp客户端,在子线程轮询接收数据,接收到的数据通过回调函数传递给mainwindow主线程处理,界面按钮发送tcp数据。
pro工程文件添加
win32{
LIBS += -lws2_32}
tcpclient.h
#ifndef TCPCLIENT_H
#define TCPCLIENT_H
#include <stdint.h>
#include <pthread.h>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#define socklen_t int
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#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 <QDebug>
#include <QThread>
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 <stdint.h>
#include <pthread.h>
#ifdef _WIN32
#define _WIN32_WINNT 0x0600
#include "windows.h"
#include <winsock2.h>
#include <ws2tcpip.h>
#define socklen_t int
#else
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#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 <stddef.h>
#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 <QDebug>
#include <QThread>
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);
}
边栏推荐
- 我在京东使用工厂模式,一文说清楚工厂模式
- Summary in the development process BaseService provides a public access service file for all controllers or services to reduce repeated injection
- 如何保护 JDBC 应用程序免受 SQL 注入
- Report on the progress of writing Chinese experiments by latex
- Codeforces Round #809 (Div. 2)(C和D1两题)
- 微信小程序项目实战
- 一文深入浅出理解国产开源木兰许可系列协议
- Overview of multisensor fusion -- FOV and bev
- [ssm] unified result encapsulation
- Wechat hotel reservation applet graduation project (8) graduation project thesis template
猜你喜欢
![[untitled] share an API Gateway project developed based on ABP vNext](/img/94/bfa4fa36e4974830e6afac118a593e.png)
[untitled] share an API Gateway project developed based on ABP vNext

景联文科技提供3D点云-图像标注服务

Copytexture, copytoresolvetarget of UE4 engine

VScode配置用户代码片段

Draw a wave ball with the curve of flutter and Bessel

I use the factory mode in jd.com and explain the factory mode clearly

记一次线上SQL死锁事故:如何避免死锁?

002_Kubernetes安装配置

驱动页面性能优化的3个有效策略

“蔚来杯“2022牛客暑期多校训练营1 (部分题目总结)
随机推荐
局域网SDN硬核技术内幕 22 亢龙有悔——规格与限制(下)
Chapter 2 how to use sourcetree to update code locally
zabbix agent创建监控项
BGP笔记(二)
Codeforces Round #809 (Div. 2)(C和D1两题)
Leetcode 757 set the intersection size to at least 2[sort greedy] the leetcode path of heroding
船新 IDEA 2022.2 正式发布,新特性真香
The new idea 2022.2 was officially released, and the new features are really fragrant
聊聊并发编程的12种业务场景
信息系统项目管理师必背核心考点(四十九)合同法
LAN SDN technology hard core insider 4 from computing virtualization to network virtualization
基于ROS的导航框架
微信小程序项目实战
景联文科技提供3D点云-图像标注服务
Is cross modal semantic alignment optimal under comparative learning--- Adaptive sparse attention alignment mechanism IEEE trans MultiMedia
类和对象(1)
Small program completion work wechat campus second-hand book trading small program graduation design finished product (2) small program function
About redis, do you update the database first or the cache first?
网络安全之ARP欺骗防护
Wechat campus second-hand book trading applet graduation design finished product (8) graduation design thesis template