0
点赞
收藏
分享

微信扫一扫

安全传输平台项目——统一通信组件-统一共享内存组件


在学习安全传输平台项目总结了笔记,并分享出来

10-安全传输平台项目-第04天(统一通信组件-统一共享内存组件)

 

一、复习

1、wind下制作动态库
2、linux下制作动态库
3、makefile复习
4、统一通信组件—socket通信
5、统一通信组件-服务器端实现



#include <stdio.h>#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

#include "poolsocket.h"

void *start_routine(void * arg)
{
int ret;
int timeout = 3;
int connfd = (int)arg;

unsigned char *out = NULL;
int outlen = 0;

while (1) {

//服务器端端接受报文
ret = sckServer_rev(connfd, timeout, &out, &outlen);
if (ret == Sck_ErrPeerClosed) {
// 检测到 对端关闭,关闭本端。
printf("----------------ErrPeerClosed 关闭服务器\n");
break;
} else if (ret == Sck_ErrTimeOut) {
printf("---服务器检测到客户端发送数据 超时 \n");
continue;
} else if (ret != 0) {
printf("未知错误\n");
break;
}

// 处理数据。 ----- 回射
printf("====客户端发送了:%s\n", out);

//服务器端发送报文
ret = sckServer_send(connfd, timeout, out, outlen);
if (ret == Sck_ErrPeerClosed) {
// 检测到 对端关闭,关闭本端。
printf("---ErrPeerClosed \n");
break;
} else if (ret == Sck_ErrTimeOut) {
printf("---服务器检测到本端发送数据 超时 \n");
continue;
} else if (ret != 0) {
printf("未知错误\n");
break;
}
}
sckServer_close(connfd);
return NULL;
}

int main(void)
{
int listenfd;
int port = 8080;
int ret = 0;

int timeout = 3;
int connfd = -1;

pthread_t pid;

//服务器端初始化
ret = sckServer_init(port, &listenfd);
if (ret != 0) {
printf("sckServer_init error %d\n", ret);
return ret;
}

while (1) {
ret = sckServer_accept(listenfd, timeout, &connfd);
if (ret == Sck_ErrTimeOut){
printf("-----客户端连接超时----\n");
continue;
} else if(ret != 0) {
printf("sckServer_accept error %d\n", ret);
return ret;
}
ret = pthread_create(&pid, NULL, start_routine, (void *)connfd);
}

//服务器端环境释放
sckServer_destroy();

return 0;
}
server.c

 

二、安全传输平台项目—统一通信组件

1、客户端连接服务器

》编写client.c



#include <stdio.h>#include <stdlib.h>#include <string.h>
#include <unistd.h>
#include <pthread.h>

#include "poolsocket.h"

int main(void)
{
char *ip = "127.0.0.1";
int port = 8080;
int time = 3;
int connfd = -1;
int ret = -1;

unsigned char *data = "abcdefg";
int datalen = 5;

unsigned char *out = NULL;
int outlen = -1;

//客户端 初始化
ret = sckClient_init();
if (ret != 0) {
printf("sckClient_init error %d\n", ret);
return ret;
}

while (1) {

//客户端 连接服务器
ret = sckClient_connect(ip, port, time, &connfd);
if (ret == Sck_ErrTimeOut) {
printf("---客户端连接服务器 超时 \n");
continue;
} else if (ret != 0) {
printf("客户端连接服务器 失败: errorNO:%d\n", ret);
break;
}

//客户端 发送报文
ret = sckClient_send(connfd, time, data, datalen);
if (ret == Sck_ErrPeerClosed) {
printf("---服务器关闭,客户端断开连接 \n");
break;
} else if (ret == Sck_ErrTimeOut) {
printf("---服务器接收数据 超时 \n");
continue;
} else if (ret != 0) {
printf("客户端发送数据失败:errorNO:%d\n", ret);
break;
}
sleep(1);

//客户端 接受报文
ret = sckClient_rev(connfd, time, &out, &outlen);
if (ret == Sck_ErrPeerClosed) {
printf("---服务器关闭,客户端断开连接 \n");
break;
} else if (ret == Sck_ErrTimeOut) {
printf("---服务器发送数据 超时 \n");
continue;
} else if (ret != 0) {
printf("客户端接收数据失败:errorNO:%d\n", ret);
break;
}
}

//客户端 关闭和服务端的连接
if (connfd != -1)
sckClient_closeconn(connfd);

//客户端 释放
sckClient_destroy();

return 0;
}

client.c

创建目录test,把makefile、libitcastsocket.so、poolsocket.h放入test目录下。

>make

安全传输平台项目——统一通信组件-统一共享内存组件_客户端

>./server

打开另一个终端,切换到test目录下,执行>./client,然后查看原终端的数据接收情况。

注意中文乱码,需要转换:

安全传输平台项目——统一通信组件-统一共享内存组件_客户端_02

安全传输平台项目——统一通信组件-统一共享内存组件_客户端_03

为什么会出现服务器检测到客户端发送数据超时?

 

2、客户端连接池连接服务器

》编写client2.c

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>
#include <pthread.h>

#include "poolsocket.h"

/*
typedef struct _SCKClitPoolParam
{
char serverip[64];
int serverport;
int bounds; //池容量
int connecttime;
int sendtime;
int revtime;
}SCKClitPoolParam;
*/

void *mystart_routin(void *arg)
{
int ret = 0;
int connfd = -1;
void *handle = arg;

unsigned char *data = "abcdefg";
int datalen = 5;

unsigned char *out = NULL;
int outlen = -1;

// 获取一条连接池中的链接:
ret = sckCltPool_getConnet(handle, &connfd);
if (ret != 0) {
printf("从连接池 获取 连接失败:%d\n", ret);
return NULL;
}
//可以增加发送数据的次数,flag=10,flag--
while (1) {
ret = sckCltPool_send(handle, connfd, data, datalen);
if (ret == Sck_ErrPeerClosed) {
printf("---服务器关闭,客户端断开连接 \n");
break;
} else if (ret == Sck_ErrTimeOut) {
printf("---服务器接收数据 超时 \n");
continue;
} else if (ret != 0) {
printf("客户端发送数据失败:errorNO:%d\n", ret);
break;
}

ret = sckCltPool_rev(handle, connfd, &out, &outlen);
if (ret == Sck_ErrPeerClosed) {
printf("---服务器关闭,客户端断开连接 \n");
break;
} else if (ret == Sck_ErrTimeOut) {
printf("---服务器发送数据 超时 \n");
continue;
} else if (ret != 0) {
printf("客户端接收数据失败:errorNO:%d\n", ret);
break;
}
printf("------接收到 服务器回发数据:%s\n", out);
}
sckCltPool_putConnet(handle, connfd, 0);


return NULL;
}


int main(void)
{
int i = 0;
int ret = 0;
pthread_t pidArray[6] = {0};

SCKClitPoolParam clientPoolparam;
strcpy(clientPoolparam.serverip, "127.0.0.1");
clientPoolparam.serverport = 8080;
clientPoolparam.bounds = 10;
clientPoolparam.connecttime = 3;
clientPoolparam.sendtime = 3;
clientPoolparam.revtime = 3;

void *handle = NULL;

//客户端 初始化
ret = sckCltPool_init(&handle, &clientPoolparam);
if (ret != 0) {
printf("sckCltPool_init error %d\n", ret);
return ret;
}

while (1) {

for (i = 0; i < 6; i++) {
pthread_create(&pidArray[i], NULL, mystart_routin, handle); //需要判断返回值
}

for (i = 0; i< 6; i++) {
pthread_join(pidArray[i], NULL);
}
}

//销毁连接池
sckCltPool_destroy(handle);

return 0;
}

client2.c

>make

>./server

打开另一个终端,切换到test目录下,执行>./client,然后查看原终端的数据接收情况。

 

3、线程传参现象展示

>vi a_server.c

#include <unistd.h>#include <sys/types.h>#include <signal.h>#include <sys/wait.h>#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include "poolsocket.h"


void *mystart_routine(void *arg)
{
int ret = 0;
int timeout = 3;
int connfd = (int)arg;

unsigned char *out = NULL;
int outlen = 0;

while (1)
{
//服务器端端接受报文
ret = sckServer_rev(connfd, timeout, &out, &outlen); //1
if (ret == Sck_ErrPeerClosed)
{
//printf("aaaaa \n");
printf("服务器端检测到客户端有一条连接已关闭 \n");
break;
}
else if (ret == Sck_ErrTimeOut)
{
printf("服务器端send超时\n");
continue;
}
else if (ret != 0)
{
printf("服务器端 sckServer_send() err\n");
break;
}

printf("out:%s \n", out); //回射

//服务器端发送报文
ret = sckServer_send(connfd, timeout, out, outlen);
if (ret == Sck_ErrPeerClosed)
{
sck_FreeMem((void **)&out);
printf("服务器端检测到客户端有一条连接已关闭\n");
break;
}
else if (ret == Sck_ErrTimeOut)
{
sck_FreeMem((void **)&out);
printf("服务器端send超时\n");
continue;
}
else if (ret != 0)
{
sck_FreeMem((void **)&out);
printf("服务器端 sckServer_send() err\n");
break;
}
sck_FreeMem((void **)&out);
}

sckServer_close(connfd);
return NULL;
}


int main()
{
int ret = 0;
int port = 8001;
int listenfd = 0;
int timeout = 3;
int connfd = 0;
pthread_t pid;


//函数声明
//服务器端初始化
ret = sckServer_init(port, &listenfd);
if (ret != 0)
{
printf("func sckServer_init() err:%d \n", ret);
return ret;
}

while (1)
{
ret = sckServer_accept(listenfd, timeout, &connfd);
if (ret == Sck_ErrTimeOut)
{
printf("func sckServer_accept() Sck_ErrTimeOut\n");
continue;
}
else if (ret != 0)
{
ret = 2;
printf("fun sckServer_accept() err :%d \n", ret);
break;
}

pthread_create(&pid, NULL, mystart_routine, (void *)(connfd));

}


//服务器端环境释放
int sckServer_destroy();
printf("hello....\n");
}

a_server.c

>vi a_client3err.c


#include <unistd.h>#include <sys/types.h>#include <signal.h>#include <sys/wait.h>#include <stdlib.h>#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include "poolsocket.h"

typedef struct _ThreadInfo
{
void *handle;
int iLoop;
int iArrayIndex; //线程数组的下标
}ThreadInfo;


void* myclient_startroutine (void *arg)
{
int i = 0, ret = 0;
int connfd = 0;

char data[64] = {0};
int datalen = 0;

unsigned char *out = NULL;
int outlen = 0;

ThreadInfo *pThreadInfo = (ThreadInfo *)arg;
void *handle = pThreadInfo->handle; //


//客户端 socket池 获取一条连接
ret = sckCltPool_getConnet(handle, &connfd);
if (ret != 0)
{
printf("func sckCltPool_getConnet() err:%d\n", ret);
return NULL;
}

for (i=0; i<pThreadInfo->iLoop; i++)
{
//客户端 socket池 发送数据
memset(data, 0, sizeof(data));
sprintf(data, "第%d线程, 第%d圈", pThreadInfo->iArrayIndex, i+1);

ret = sckCltPool_send(handle, connfd, data, strlen(data));
if (ret == Sck_ErrPeerClosed)
{
printf("sckCltPool_send 客户端检测到 服务器已经关闭 退出\n");
break;
}
else if (ret == Sck_ErrTimeOut)
{
printf(" sckCltPool_send timeout \n");
break;
}
else if (ret != 0)
{
printf("fun sckServer_rev() err:%d \n", ret);
break;
}

//客户端 socket池 接受数据
ret = sckCltPool_rev(handle, connfd, &out, &outlen); //1
if (ret == Sck_ErrPeerClosed)
{
printf("sckCltPool_rev 客户端检测到 服务器已经关闭 退出\n");
break;
}
else if (ret == Sck_ErrTimeOut)
{
printf(" sckCltPool_rev timeout \n");
break;
}
else if (ret != 0)
{
printf("fun sckCltPool_rev() err:%d \n", ret);
break;
}
printf("客户端 out:%s \n", out);
sck_FreeMem((void **)&out);
}

//客户端 socket池 把连接放回 socket池中
sckCltPool_putConnet(handle, connfd, 0); //0正常 1

return NULL;
}

int main(void)
{
int ret = 0, i = 0;
char *ip = "127.0.0.1";
int port = 8001;
int time = 3;
int connfd = 0;

int iLoop = 0; //圈数
int iThreadNum = 0 ; //线程数

void *handle = NULL;
pthread_t pidArray[1024];

ThreadInfo threadInfo;
memset(&threadInfo, 0, sizeof(ThreadInfo));

SCKClitPoolParam sckClitPoolParm;
memset(&sckClitPoolParm, 0, sizeof(SCKClitPoolParam));
strcpy(sckClitPoolParm.serverip, "127.0.0.1");
sckClitPoolParm.serverport = 8001;
sckClitPoolParm.bounds = 10;
sckClitPoolParm.connecttime = 3;
sckClitPoolParm.sendtime = 3;
sckClitPoolParm.revtime = 3;


printf("\n请输入线程的个数: ");
scanf("%d", &iThreadNum);

printf("\n请输入每个线程运行圈数: ");
scanf("%d", &iLoop);

if (iThreadNum >= 1024)
{
printf("iThreadNum大于1024\n");
return 0;
}

//客户端 socket池初始化
ret = sckCltPool_init(&handle, &sckClitPoolParm);
if (ret != 0)
{
printf("func sckCltPool_init() err:%d \n ", ret);
return ret;
}

//启动多线程
for (i=0; i<iThreadNum; i++)
{
threadInfo.handle = handle; //alt + 鼠标键左键拖动
threadInfo.iLoop = iLoop;
threadInfo.iArrayIndex = i + 1;
pthread_create(&pidArray[i], NULL, myclient_startroutine, (void *)&threadInfo);
}


//主进程 等待子线程 结束
for (i=0; i<iThreadNum; i++)
{
pthread_join(pidArray[i], NULL);
}


//客户端 socket池 销毁连接
sckCltPool_destroy(handle);

printf("client hello....\n");


return 0;
}

a_client3err.c

>make

>./a_server

打开另一个终端,切换到test目录下,执行>./a_client3err,然后查看原终端的数据接收情况。

安全传输平台项目——统一通信组件-统一共享内存组件_#include_04

安全传输平台项目——统一通信组件-统一共享内存组件_服务器_05

1)问题:pthread_create(&pidArray[i], NULL, myclient_startroutine, (void *)&threadInfo);中的最后一个参数需要加地址符号吗?

由于threadInfo是一个结构体,从大小及值拷贝需要的空间复杂度考虑,所以必须传入地址,不能传值。结论——结构体做参数,最好传地址!!!

2)问题:每次都是最后一个线程跑圈?

分析:pthread_create传参最后一个参数threadInfo使用了地址传参。需要看4、线程传参内存冗余法

 

4、线程传参内存冗余法

》内存冗余分析图:

安全传输平台项目——统一通信组件-统一共享内存组件_服务器_06

注意:形参和局部变量地位等同,都位于栈上。

原因:线程子函数栈空间调用了main函数栈空间的值,当线程几乎同时创建时,去读取main栈空间的值时,main栈空间的值i还在变化(自增)。所以需要为每个线程子函数创建属于自己的栈空间。

>vi a_client4.c


#include <unistd.h>#include <sys/types.h>#include <signal.h>#include <sys/wait.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>
#include <string.h>
#include <pthread.h>
#include "poolsocket.h"

typedef struct _ThreadInfo
{
void *handle;
int iLoop;
int iArrayIndex;//线程数组的下标
}ThreadInfo;


void* myclient_startroutine (void *arg)
{
int i = 0, ret = 0;
int connfd = 0;

char data[64] = {0};
int datalen = 0;

unsigned char *out = NULL;
int outlen = 0;

ThreadInfo *pThreadInfo = (ThreadInfo *)arg;
void *handle = pThreadInfo->handle; //


//客户端 socket池 获取一条连接
ret = sckCltPool_getConnet(handle, &connfd);
if (ret != 0)
{
printf("func sckCltPool_getConnet() err:%d\n", ret);
return NULL;
}

for (i=0; i<pThreadInfo->iLoop; i++)
{
//客户端 socket池 发送数据
memset(data, 0, sizeof(data));
sprintf(data, "第%d线程, 第%d圈", pThreadInfo->iArrayIndex, i+1);
ret = sckCltPool_send(handle, connfd, data, strlen(data));
if (ret == Sck_ErrPeerClosed)
{
printf("sckCltPool_send 客户端检测到 服务器已经关闭 退出\n");
break;
}
else if (ret == Sck_ErrTimeOut)
{
printf(" sckCltPool_send timeout \n");
break;
}
else if (ret != 0)
{
printf("fun sckServer_rev() err:%d \n", ret);
break;
}

//客户端 socket池 接受数据
ret = sckCltPool_rev(handle, connfd, &out, &outlen); //1
if (ret == Sck_ErrPeerClosed)
{
printf("sckCltPool_rev 客户端检测到 服务器已经关闭 退出\n");
break;
}
else if (ret == Sck_ErrTimeOut)
{
printf(" sckCltPool_rev timeout \n");
break;
}
else if (ret != 0)
{
printf("fun sckCltPool_rev() err:%d \n", ret);
break;
}
printf("客户端 out:%s \n", out);
sck_FreeMem((void **)&out);
}

//客户端 socket池 把连接放回 socket池中
sckCltPool_putConnet(handle, connfd, 0); //0正常 1

if (arg != NULL) free(arg);

return NULL;
}

int main()
{
int ret = 0, i = 0;
char *ip = "127.0.0.1";
int port = 8001;
int time = 3;
int connfd = 0;

int iLoop = 0; //圈数
int iThreadNum = 0 ; //线程数

void *handle = NULL;
pthread_t pidArray[1024];

//ThreadInfo threadInfo;
//memset(&threadInfo, 0, sizeof(ThreadInfo));

SCKClitPoolParam sckClitPoolParm;
memset(&sckClitPoolParm, 0, sizeof(SCKClitPoolParam));
strcpy(sckClitPoolParm.serverip, "127.0.0.1");
sckClitPoolParm.serverport = 8001;
sckClitPoolParm.bounds = 20; //node: 客户端线程池的个数是10个
sckClitPoolParm.connecttime = 3;
sckClitPoolParm.sendtime = 3;
sckClitPoolParm.revtime = 3;


printf("\n请输入线程的个数: ");
scanf("%d", &iThreadNum);

printf("\n请输入每个线程运行圈数: ");
scanf("%d", &iLoop);

if (iThreadNum >= 1024)
{
printf("iThreadNum大于1024\n");
return 0;
}

//客户端 socket池初始化
ret = sckCltPool_init(&handle, &sckClitPoolParm);
if (ret != 0)
{
printf("func sckCltPool_init() err:%d \n ", ret);
return ret;
}

//启动多线程
for (i=0; i<iThreadNum; i++)
{
ThreadInfo *pInfo = (ThreadInfo *)malloc(sizeof(ThreadInfo));
pInfo->handle = handle; //alt + 鼠标键左键拖动
pInfo->iLoop = iLoop;
pInfo->iArrayIndex = i + 1;
pthread_create(&pidArray[i], NULL, myclient_startroutine, (void *)pInfo);
}


//主进程 等待子线程 结束
for (i=0; i<iThreadNum; i++)
{
pthread_join(pidArray[i], NULL);
}


//客户端 socket池 销毁连接
sckCltPool_destroy(handle);

printf("client hello....\n");
return 0;
}

a_client4.c

>make

>./a_server

打开另一个终端,切换到test目录下,执行>./a_client4,然后查看原终端的数据接收情况。

安全传输平台项目——统一通信组件-统一共享内存组件_客户端_07

 

三、安全传输平台项目—统一共享内存组件

1、常见IPC

 

2、简单内存模型分析

 

3、共享内存操作函数—shmget

 

4、共享内存操作函数—shmat_dt

 

5、共享内存操作函数—shmctl

 

6、Linux内核管理共享内存方法

 

7、共享内存操作函数接口

 

 

四、客户端服务器密钥协商预说明

安全传输平台项目——统一通信组件-统一共享内存组件_客户端_08

 

在学习安全传输平台项目总结了笔记,并分享出来

举报

相关推荐

0 条评论