分析
上一节我们完成了GTK图像框架的diamante编写,现在需要把网络子系统加入到这个框架中。再这个框架中我们需要添加2个功能,一个是建立和服务器的连接,另一个是显示当前的图像。这2个功能分别和2个窗口对于,在登录窗口实现和服务器的连接,在主窗口实现图像的显示。
实现
建立服务器的连接在connect_handler函数中通过调用tcp_init_net函数来实现,tcp_init_net函数如下:
/*客户端TCP连接初始化*/
int tcp_init_net(char *ip, int port)
{
int sock;
struct sockaddr_in addr;
sock = socket(AF_INET, SOCK_STREAM, 0);
addr.sin_addr.s_addr = inet_addr(ip);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
if (connect(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1)
{
close(sock);
return -1;
}
return sock;
}
图像的显示我们通过一个线程来完成,在这个线程里面做这些事情:
1、判断是否要继续发送,如果是执行下面的步骤,否则退出
2、构造请求图像请求
3、发送图像请求
4、接收图像数据
5、把图像在GTK中显示
/*请求图片的线程函数*/
void * video_thread(void *arg)
{
int len;
struct wcam_cli *client = (struct wcam_cli *)arg;
__u8 *rsp = client->rsp;
int size;
while(!(client->stop))
{
//1、发送图像请求
//1.1构造图像请求
len = make_request(client->req, VID_REQ_FRAME, NULL);
//1.2发送图像请求
send(client->sock, client->req, len, 0);
//2、接收图像
//先接收头部信息,3个字节
len = FRAME_HDR_SZ;
recv(client->sock, rsp, len, MSG_WAITALL);//MSG_WAITALL表示需要读全
//接收len
rsp += FRAME_HDR_SZ;
len = client->rsp[LEN_POS];
recv(client->sock, rsp, len, MSG_WAITALL);
memcpy(&size, rsp, len);//获取len的值,放在size中
//接收数据
rsp += len;
recv(client->sock, rsp, size, MSG_WAITALL);
//3、把图像交给显示子系统
draw_video_frame(rsp, size, client->arg);
//usleep(10000);
}
}
同时建立一个网络子系统初始化的函数,它在建立连接之后执行:
/*网络系统初始化*/
void net_sys_init(struct wcam_win *c)
{
pthread_t tid;
struct wcam_cli *client;
client = calloc(1, sizeof(struct wcam_cli));
//初始化client结构
client->stop = false;
client->arg = c;
client->sock = c->entry_win->sock;
c->client = client;
//构建工作线程
pthread_create(&tid, NULL, video_thread, client);
}
最后把这些代码整合到之前的GTK框架中,调试成功,完整的代码如下:
https://github.com/dayL-W/Video-capture-system