基于多线程多客户端连接的TCP模型
程序员文章站
2024-03-23 10:02:10
...
前言
前面已经写了一篇简单的TCP模型,用于单线程单客户端链接,这种效率最高,但是适用场景也是最小的。今天再测试一番简单的多线程多客户端连接的TCP模型。== 这种模型目前也不常见,因为已经有很多的IO复用模型了 ==。但是基于对循序渐进的尊重,我依旧对这个模型进行了一次实验。
- 服务端
主线程中循环调用accept函数接收新的连接,每收到一个连接之后开启一个接收线程接收对端的发送;可以进行注册回调函数的方式处理收到的数据
mth_srv.c
/*!
* \file mth_srv.c
* \date 2019/10/12 16:47
*
* \author locki
* Contact: [email protected]
*
* \brief 多线程处理多连接
*
* TODO: long description
*
* \note
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#include "mth_srv.h"
srv_msg_t mgr ;
void* cli_proc(void* argv) {
cli_node_t* client = (cli_node_t*)argv;
int len = 0;
char buf[1024] = { 0 };
while (len = recv(client->_fd, buf, 1024, 0) > 0) {
if (mgr._on_recv != NULL)
mgr._on_recv(client->_fd, buf, len, mgr.hint);
printf("recv: %s\n", buf);
}
// 对端断开;需要将管理中此客户端置为断开
client->_status = SOCK_DISCON;
close(client->_fd);
}
int test_mthsrv(int argc, char** argv)
{
int ret = 0;
int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
mgr._fd = fd;
struct sockaddr_in srvaddr = { 0 };
inet_aton("127.0.0.1", &srvaddr.sin_addr);
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = htons(8888);
if (-1 == bind(fd, (struct sockaddr*)&srvaddr, sizeof(srvaddr))) {
printf("bind failed errno:%d", errno);
goto SOCKEXIT;
}
mgr._addr = srvaddr;
if (-1 == (ret = listen(fd, 10))) {
printf("listen 10 failed;errno:%d\n", errno);
goto SOCKEXIT;
}
printf("listening...\n");
while (mgr._cli_count < MAX_CLIENT) {
int clifd = 0;
struct sockaddr_in cliaddr = { 0 };
socklen_t len = sizeof(cliaddr);
if (-1 == (clifd = accept(fd, (struct sockaddr*)&cliaddr, &len))) {
printf("accept failed:%d\n", errno);
goto SOCKEXIT;
}
printf("new client, %s:%d fd = %d", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port), clifd);
// 有新客户端连接;
cli_node_t* climgr = (cli_node_t*)calloc(1, sizeof(cli_node_t));
climgr->_fd = clifd;
climgr->_addr = cliaddr;
mgr.cli[mgr._cli_count++] = climgr;
// 启动一个客户端线程
if (0 == pthread_create(&climgr->_thread_id, NULL, cli_proc, climgr)) {
printf("new thread created\n");
}
}
// 客户端过多;
printf("client nums is %d ---\n", mgr._cli_count);
SOCKEXIT:
close(fd);
return ret;
}
mth_srv.h
/*!
* \file mth_srv.h
* \date 2019/10/12 16:55
*
* \author locki
* Contact: [email protected]
*
* \brief 多线程socket头文件
*
* TODO: long description
*
* \note
*/
typedef struct cli_node_s cli_node_t;
typedef struct srv_mgr_s srv_msg_t;
typedef int(*onrecv)(int fd, char* data, int datalen, void* hint);
#define MAX_CLIENT 100
#define SOCK_CONN 1
#define SOCK_DISCON 2
struct cli_node_s {
int _fd; /**< 连接fd */
int _status; /**< 客户端连接状态 */
struct sockaddr_in _addr; /**<当前客户端信息 */
pthread_t _thread_id; /**< 当前线程ID */
};
struct srv_mgr_s {
int _fd; /**< 服务端fd */
int _cli_count; /**< 客户端数量 */
cli_node_t* cli[MAX_CLIENT]; /**< 客户端信息 */
struct sockaddr_in _addr; /**<当前服务端端信息 */
onrecv _on_recv; /**< 接收回调 */
void* hint;
};
#pragma once
- 客户端
客户端开启多个连接,然后使用每个连接发送数据到客户端
mth_cli.c
/*!
* \file mth_cli.c
* \date 2019/10/14 19:53
*
* \author ycd
* Contact: [email protected]
*
* \brief 多连接测试客户端
*
* TODO: long description
*
* \note
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int test_mthcli(int argc, char** argv)
{
int ret = 0;
int mthcli[100] = { 0 };
for (int i = 0; i < 100; i++) {
mthcli[i] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in addr = { 0 };
addr.sin_addr.s_addr = inet_addr("192.168.0.195");
addr.sin_port = htons(8888);
addr.sin_family = AF_INET;
ret = connect(mthcli[i], (struct sockaddr*)&addr, sizeof(addr));
if (ret == -1) {
printf("connect to host failed, errno:%d\n", errno);
continue;
}
printf("connect to host success\n");
}
char buf[32] = { 0 };
while (1) {
sprintf(buf, "%d", time(NULL));
for (int i = 0; i < 100; i++) {
ret = send(mthcli[i], buf, 32, 0);
if (ret == -1) {
printf("send to host failed: id= %d errno = %d\n", i, errno);
}
}
usleep(1000);
printf("send success\n");
}
}
上一篇: Java网络编程UDP协议发送接收数据
下一篇: 网络编程TCP协议发送和接收数据