求个中土世界战争之影3dm的百度网盘下载

1280人阅读
dm3730(8)
cvbs输出芯片SAA7171
多路采集芯片TW2864 TVP5158
八路的视频监控采集卡有很多种
八个视频加八个音频,
如TW6818 TW6816 TW6802B芯片的 OR-6908B OR-6808B OR-408C型号
八个视频加四个音频,
如TW6805A OR-408D型号的就是八路视频,四路音频
八个视频不带音频。
如飞利蒲7130芯片卡的八路OR-408B型号只有八路视频不带音频
还有PCI-E的采集卡也只有八路视频OR-HD8型号。
我们先来介绍视频的采集和预处理部分。
视频采集芯片我们采用的是可以支持4路视频输入的TW2835。可以达到D1的视频效果,完全满足基本的视频监控需求
Techwell公司推出了 TW2835 四信道视频和音频控制器。建立在 TW2834 的成功基础之上,TW2835 将6个主要程序整合进一个芯片中,其中包括:4个高质量的 NTSC/PAL 视频解码器、4个音频模拟数字转换器、一个音频复用器,双色显示控制器,双视频译码器以及一个先进的 OSD(屏幕菜单式调节方式)。此外,TW2835 每个芯片还使用了一个单一的同步动态存储器 (SDRAM),可用于可选的 BGA 包中,还拥有一个被称为 TW2836 的 pin-to-pin(管脚到管脚)姊妹芯片。TW2836 除了不包含音频之外,与 TW2835 具有同样的功能。TW2835 利用了 Techwell 安全监控集成电路产品解决方案的广泛组合,是帮助 DVR(数码视频录像机)生产商提高质量与功能、加快上市时间以及减少成本的重要一步。在其众多功能中,TW2835 支持详尽的实时 D1 录制、在重放过程中将信道 ID 信息添加到视频流媒体中,用于自动解码与显示,同时还包含一个5层的图形覆盖功能,为 OSD、单盒、2D 阵列箱以及鼠标指示器显示特征/位图。TW2835 还包含一个简单的界面,使用多段连接支持多达16个信道系统。此外,TW2835 还嵌入了几种特别的监视功能,其中包括:运动监测、放大以及水平与垂直缩放控制。凭借置入旨在减少交叉噪音的反锯齿过滤器和高质量的梳状过滤器,TW2835 已经成为一种针对 DVR 与 Quad/Multiplexers 的高性能、具有成本效益的解决方案。
tw2835比较灵活,既可以单路切换采集4路D1视频,也可以将4路视频集成到1路D1视频输出,可以根据你的需求在应用程序上控制。成都莱得科技()提供的驱动程序给应用程序提供了控制接口。并且提供完整的驱动程序源代码,该方案和代码在客户的实际产品中获得了成功的验证。现在我们简要的介绍一下tw2835在mx27开发板中的驱动编写和遇到的一些问题。
一、驱动的架构和实现
tw2835和mx27的视频流传输是通过mx27的CSI接口,命令控制接口采用I2C
也就是是说驱动分为两个部分
负责初始化和配置芯片,例如设置和获取颜色,复位芯片,设置通道属性,检测芯片的存在与否,设置csi接口的时钟等
//驱动初始化
static __init int tw2835_init(void)
gpio_tw2835_active();
err = i2c_add_driver(&tw2835_i2c_driver);
//首先要对硬件引脚功能进行初始化,
void gpio_tw2835_active(void)
//设置CSI接口的引脚功能
gpio_request_mux(MX27_PIN_CSI_D0, GPIO_MUX_PRIMARY);
gpio_request_mux(MX27_PIN_CSI_D1, GPIO_MUX_PRIMARY);
gpio_request_mux(MX27_PIN_CSI_D2, GPIO_MUX_PRIMARY);
gpio_request_mux(MX27_PIN_CSI_D3, GPIO_MUX_PRIMARY);
gpio_request_mux(MX27_PIN_CSI_D4, GPIO_MUX_PRIMARY);
gpio_request_mux(MX27_PIN_CSI_MCLK, GPIO_MUX_PRIMARY);
gpio_request_mux(MX27_PIN_CSI_PIXCLK, GPIO_MUX_PRIMARY);
gpio_request_mux(MX27_PIN_CSI_D5, GPIO_MUX_PRIMARY);
gpio_request_mux(MX27_PIN_CSI_D6, GPIO_MUX_PRIMARY);
gpio_request_mux(MX27_PIN_CSI_D7, GPIO_MUX_PRIMARY);
gpio_request_mux(MX27_PIN_CSI_VSYNC, GPIO_MUX_PRIMARY);
gpio_request_mux(MX27_PIN_CSI_HSYNC, GPIO_MUX_PRIMARY);
/* Power down control */
mdelay(10);
gpio_request_mux(MX27_PIN_USBH1_RXDM, GPIO_MUX_GPIO);
mxc_set_gpio_direction(MX27_PIN_USBH1_RXDM, 0);
mxc_set_gpio_dataout(MX27_PIN_USBH1_RXDM, 1);
/* Reset芯片 */
mdelay(10);
gpio_request_mux(MX27_PIN_CSPI1_RDY, GPIO_MUX_GPIO);
mxc_set_gpio_direction(MX27_PIN_CSPI1_RDY, 0);
mxc_set_gpio_dataout(MX27_PIN_CSPI1_RDY, 0);
mdelay(10);
mxc_set_gpio_dataout(MX27_PIN_CSPI1_RDY, 1);
mdelay(10);
然后,进行调用i2c驱动接口,i2c_add_driver ,加入新的驱动。由框架自动调用attach函数
在该函数中,设定tw2835的主时钟,然后调用i2c_probe进行芯片的地址检测
static int tw2835_attach(struct i2c_adapter *adap)
uint32_t mclk = ;
struct clk *
clk = clk_get(NULL, "csi_clk");
clk_enable(clk);
set_mclk_rate(&mclk);
err = i2c_probe(adap, &addr_data, &tw2835_detect_client);
clk_disable(clk);
clk_put(clk);
在扫描到芯片的地址和预置的地址一致的时候,调用tw2835_detect_client
define TW2835_I2C_ADDRESS
0x42 //tw2835的i2c地址
define TW2835_DEVICE_ID
0x05 //芯片内部的id,从寄存器中读出
1.调用i2c_attach_client将adapter设置到tw2835_i2c_client中
2.将tw2835_i2c_client加入到i2c设备列表中去
3.分配一个摄像头接口数据,设置主时钟
static int tw2835_detect_client(struct i2c_adapter *adapter, int address,
tw2835_i2c_client.adapter =
if (i2c_attach_client(&tw2835_i2c_client)) {
tw2835_i2c_client.adapter = NULL;
printk(KERN_ERR “tw2835_detect_client: i2c_attach_client failed\n”);
return -1;
interface_param = (sensor_interface *)
kmalloc(sizeof(sensor_interface), GFP_KERNEL);
if (!interface_param) {
printk(KERN_ERR "tw2835_detect_client: kmalloc failed \n");
return -1;
interface_param-&mclk = ;
printk(KERN_INFO "TW2835 Detected\n");
struct camera_sensor camera_sensor_if = {
.set_color = tw2835_set_color,
.get_color = tw2835_get_color,
.set_ae_mode = tw2835_set_ae_mode,
.get_ae_mode = tw2835_get_ae_mode,
.set_ae = tw2835_set_ae,
.set_awb = tw2835_set_awb,
.flicker_control = tw2835_flicker_control,
.get_control_params = tw2835_get_control_params,
.config = tw2835_config,
.reset = tw2835_reset,
.get_status = tw2835_get_status,
.set_channel = tw2835_set_channel,
EXPORT_SYMBOL(camera_sensor_if);
导出camera_sensor_if,在v4l2采集驱动中被使用,用来实现该芯片的控制接口,因此如果有多个视频采集芯片驱动,那么同时只能有一个驱动导出该结构体。否则会
发生冲突。
static void tw2835_interface(sensor_interface * param, u32 width, u32 height)
param-&Vsync_pol = 0x0;
param-&clk_mode = 0x0;
param-&pixclk_pol = 0x0;
param-&data_width = 0x1;
param-&data_pol = 0x0;
param-&ext_vsync = 0x1;
param-&Vsync_pol = 0x0;
param-&Hsync_pol = 0x0;
param-&width = width - 1;
param-&height = height - 1;
param-&pixel_fmt = IPU_PIX_FMT_UYVY;
param-&mclk = ;
/* setup cropping */
g_cam-&crop_bounds.left = 0;
g_cam-&crop_bounds.width =
g_cam-&crop_bounds.top = 0;
g_cam-&crop_bounds.height =
g_cam-&crop_defrect = g_cam-&crop_
if ((g_cam-&crop_current.width & g_cam-&crop_bounds.width)
|| (g_cam-&crop_current.height & g_cam-&crop_bounds.height))
g_cam-&crop_current = g_cam-&crop_
g_cam-&streamparm.parm.capture.capturemode = 0;
g_cam-&standard.index = 0;
g_cam-&standard.id = (height == 576) ? V4L2_STD_PAL : V4L2_STD_NTSC;
g_cam-&standard.frameperiod.denominator = (height == 576) ? 50 : 60;
g_cam-&standard.frameperiod.numerator = 1;
g_cam-&standard.framelines =
在mxc_v4l2_capture.c[v4l2驱动实现]中定义了cam_data *g_我们在tw2835.c[i2c驱动]中来填充它,
设置我们需要采集的视频的制式,场数,crop的高度和宽度等。
typedef struct _cam_data {
struct video_device *video_
/* semaphore guard against SMP multithreading */
struct semaphore busy_
/* params lock for this camera */
struct semaphore param_
/* Encorder */
struct list_head ready_q;
struct list_head done_q;
struct list_head working_q;
int ping_pong_
spinlock_t int_
struct mxc_v4l_frame frame[FRAME_NUM];
wait_queue_head_t enc_
dma_addr_t rot_enc_bufs[2];
void *rot_enc_bufs_vaddr[2];
int rot_enc_buf_size[2];
enum v4l2_buf_
/* still image capture */
wait_queue_head_t still_
int still_
dma_addr_t still_
void *still_buf_
/* overlay */
struct v4l2_
struct v4l2_framebuffer v4l2_
dma_addr_t vf_bufs[2];
void *vf_bufs_vaddr[2];
int vf_bufs_size[2];
dma_addr_t rot_vf_bufs[2];
void *rot_vf_bufs_vaddr[2];
int rot_vf_buf_size[2];
bool overlay_
struct fb_info *overlay_
/* v4l2 format */
struct v4l2_format v2f;
struct v4l2_mxc_
/* V4l2 control bit */
int flicker_
/* standart */
struct v4l2_s
struct v4l2_
/* crop */
struct v4l2_rect crop_
struct v4l2_rect crop_
struct v4l2_rect crop_
int (*enc_update_eba) (dma_addr_t eba, int *bufferNum);
int (*enc_enable) (void *private);
int (*enc_disable) (void *private);
void (*enc_callback) (u32 mask, void *dev);
int (*vf_start_adc) (void *private);
int (*vf_stop_adc) (void *private);
int (*vf_start_sdc) (void *private);
int (*vf_stop_sdc) (void *private);
int (*csi_start) (void *private);
int (*csi_stop) (void *private);
/* misc status flag */
bool overlay_
bool capture_
int overlay_
int capture_
wait_queue_head_t power_
/* camera sensor interface */
struct camera_sensor *cam_
v4l2采集驱动以及显示驱动[overlay输出]
负责控制csi接口采集视频,并实现标准的的v4l2接口,给应用程序调用。这是中应用层访问视频的标志接口。
二、常见问题。
1.视频出现串扰现象
最后查出是使用了不合格的tvs管
2.视频上出现了有规则的横向水波纹
将TWV DC-DC供电改为1.8V LDO供电消除开关噪声,无水波纹出现
3.运行时1,2路的图像下部和3,4路蓝屏图像一起闪动
将TW2835的输出范围由1~254调整为16~235
4.运行一段时间后视频死掉
软件调整码流匹配
文章版权属于成都莱得科技有限责任公司所有,转载请注明出处。
网址:,联系电话:,技术交流QQ:
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:259995次
积分:3661
积分:3661
排名:第7678名
原创:90篇
转载:78篇
评论:90条
(1)(1)(2)(5)(2)(1)(1)(2)(4)(1)(10)(1)(1)(1)(1)(1)(1)(4)(1)(4)(2)(18)(17)(3)(1)(2)(1)(1)(4)(1)(8)(6)(1)(1)(6)(5)(5)(25)(1)(2)(2)(3)(1)(7)(2)(2)君,已阅读到文档的结尾了呢~~
广告剩余8秒
文档加载中
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
嵌入式Linux环境下多路音频流混音设备的研究与设计.pdf
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer--144.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口函数作用:
系统提供select函数来实现多路复用输入/输出模型。select系统调用是用来让我们的程序监视多个文件句柄的状态变化的。程序会停在select这里等待,直到被监视的文件句柄有一个或多个发生了状态改变。关于文件句柄,其实就是一个整数,我们最熟悉的句柄是0、1、2三个,0是标准输入,1是标准输出,2是标准错误输出。0、1、2是整数表示的,对应的FILE *结构的表示就是stdin、stdout、stderr。
函数原型:
int&select(int&maxfd,fd_set&*rdset,fd_set&*wrset,&\&&
&&&&&&&&&&&fd_set&*exset,struct&timeval&*timeout);&&
参数说明:
参数maxfd是需要监视的最大的文件描述符值+1;rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集 合及异常文件描述符的集合。struct timeval结构用于描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生则函数返回,返回值为0。
下面的宏提供了处理这三种描述词组的方式:
FD_CLR(inr fd,fd_set* set);用来清除描述词组set中相关fd 的位
FD_ISSET(int fd,fd_set *set);用来测试描述词组set中相关fd 的位是否为真
FD_SET(int fd,fd_set*set);用来设置描述词组set中相关fd的位
FD_ZERO(fd_set *set);用来清除描述词组set的全部位
参数timeout为结构timeval,用来设置select()的等待时间,其结构定义如下:
struct&timeval&&
&&&&time_t&tv_&&
&&&&time_t&tv_&&
如果参数timeout设为:
NULL,则表示select()没有timeout,select将一直被阻塞,直到某个文件描述符上发生了事件。
0:仅检测描述符集合的状态,然后立即返回,并不等待外部事件的发生。
特定的时间值:如果在指定的时间段里没有事件发生,select将超时返回。
函数返回值:
执行成功则返回文件描述词状态已改变的个数,如果返回0代表在描述词状态改变前已超过timeout时间,没有返回;当有错误发生时则返回-1,错误原因存于errno,此时参数readfds,writefds,exceptfds和timeout的值变成不可预测。错误值可能为:
EBADF 文件描述词为无效的或该文件已关闭
EINTR 此调用被信号所中断
EINVAL 参数n 为负值。
ENOMEM 核心内存不足
常见的程序片段如下:
fs_set readset;
FD_ZERO(&readset);
FD_SET(fd,&readset);
select(fd+1,&readset,NULL,NULL,NULL);
if(FD_ISSET(fd,readset){……}
理解select模型:
理解select模型的关键在于理解fd_set,为说明方便,取fd_set长度为1字节,fd_set中的每一bit可以对应一个文件描述符fd。则1字节长的fd_set最大可以对应8个fd。
(1)执行fd_ FD_ZERO(&set);则set用位表示是。
(2)若fd=5,执行FD_SET(fd,&set);后set变为(第5位置为1)
(3)若再加入fd=2,fd=1,则set变为
(4)执行select(6,&set,0,0,0)阻塞等待
(5)若fd=1,fd=2上都发生可读事件,则select返回,此时set变为。注意:没有事件发生的fd=5被清空。
 基于上面的讨论,可以轻松得出select模型的特点:
  (1)可监控的文件描述符个数取决与sizeof(fd_set)的值。我这边服务 器上sizeof(fd_set)=512,每bit表示一个文件描述符,则我服务器上支持的最大文件描述符是512*8=4096。据说可调,另有说虽 然可调,但调整上限受于编译内核时的变量值。本人对调整fd_set的大小不太感兴趣,参考&/CppExplore/archive//45061.html中的模型2(1)可以有效突破select可监控的文件描述符上
  (2)将fd加入select监控集的同时,还要再使用一个数据结构array保存放到select监控集中的fd,一是用于再select 返回后,array作为源数据和fd_set进行FD_ISSET判断。二是select返回后会把以前加入的但并无事件发生的fd清空,则每次开始 select前都要重新从array取得fd逐一加入(FD_ZERO最先),扫描array的同时取得fd最大值maxfd,用于select的第一个 参数。
  (3)可见select模型必须在select前循环array(加fd,取maxfd),select返回后循环array(FD_ISSET判断是否有时间发生)。
下面给一个伪码说明基本select模型的服务器模型:
array[slect_len];&&
 nSock=0;&&
 array[nSock++]=listen_(之前listen&port已绑定并listen)&&
 maxfd=listen_&&
 while(1){&&
  FD_ZERO(&set);&&
  foreach&(fd&in&array)&&
&&&&  fd大于maxfd,则maxfd=fd&&
&&&&  FD_SET(fd,&set)&&
  res=select(maxfd+1,&set,0,0,0);&&
  if(FD_ISSET(listen_fd,&set))&&
&&&&  newfd=accept(listen_fd);&&
&&&&  array[nsock++]=&&
&&&&  if(--res&=0)&continue;&&
  foreach&下标1开始&(fd&in&array)&&
&&&&  if(FD_ISSET(fd,&tyle=&COLOR:&#ff0000&&set))&&
&&&&  执行读等相关操作&&
&&&&  如果错误或者关闭,则要删除该fd,将array中相应位置和最后一个元素互换就好,nsock减一&&
&&&&  if(--res&=0)&continue;&&
检测键盘有无输入,完整的程序如下:
#include&sys/time.h&&&
#include&sys/types.h&&&
#include&unistd.h&&&
#include&string.h&&&
#include&stdlib.h&&&
#include&stdio.h&&&
int&main()&&
&&&&&&&&char&buf[10]=&&;&&
&&&&&&&&fd_set&&&
&&&&&&&&struct&timeval&&&
&&&&&&&&int&&&
&&&&&&&&FD_ZERO(&rdfds);&&
&&&&&&&&FD_SET(0,&rdfds);&&&&&
&&&&&&&&tv.tv_sec&=&3;&&
&&&&&&&&tv.tv_usec&=&500;&&
&&&&&&&&ret&=&select(1,&rdfds,NULL,NULL,&tv);&&
&&&&&&&&if(ret&0)&&
&&&&&&&&&&&&&&printf(&\n&selcet&);&&
&&&&&&&&else&if(ret&==&0)&&
&&&&&&&&&&&&&&printf(&\n&timeout&);&&
&&&&&&&&else&&
&&&&&&&&&&&&&&printf(&\n&ret&=&%d&,ret);&&
&&&&&&&&if(FD_ISSET(1,&rdfds))&&&&
&&&&&&&&{&&
&&&&&&&&&&&&&&printf(&\n&reading&);&&
&&&&&&&&&&&&&&fread(buf,9,1,stdin);&&
&&&&&&&&&}&&
&&&&&&&&&write(1,buf,strlen(buf));&&
&&&&&&&&&printf(&\n&%d&\n&,strlen(buf));&&
&&&&&&&&&return&0;&&
利用Select模型,设计的web服务器:
#include&&stdio.h&&&
#include&&stdlib.h&&&
#include&&unistd.h&&&
#include&&errno.h&&&
#include&&string.h&&&
#include&&sys/types.h&&&
#include&&sys/socket.h&&&
#include&&netinet/in.h&&&
#include&&arpa/inet.h&&&
#define&MYPORT&88960&&&&//&the&port&users&will&be&connecting&to&&
#define&BACKLOG&10&&&&&//&how&many&pending&connections&queue&will&hold&&
#define&BUF_SIZE&200&&
int&fd_A[BACKLOG];&&&&&&
int&conn_&&&&&&
void&showclient()&&
&&&&int&i;&&
&&&&printf(&client&amount:&%d\n&,&conn_amount);&&
&&&&for&(i&=&0;&i&&&BACKLOG;&i++)&{&&
&&&&&&&&printf(&[%d]:%d&&&,&i,&fd_A[i]);&&
&&&&printf(&\n\n&);&&
int&main(void)&&
&&&&int&sock_fd,&new_&&&&
&&&&struct&sockaddr_in&server_&&&&&&
&&&&struct&sockaddr_in&client_&&&
&&&&socklen_t&sin_&&
&&&&int&yes&=&1;&&
&&&&char&buf[BUF_SIZE];&&
&&&&int&&&
&&&&int&i;&&
&&&&if&((sock_fd&=&socket(AF_INET,&SOCK_STREAM,&0))&==&-1)&{&&
&&&&&&&&perror(&socket&);&&
&&&&&&&&exit(1);&&
&&&&if&(setsockopt(sock_fd,&SOL_SOCKET,&SO_REUSEADDR,&&yes,&sizeof(int))&==&-1)&{&&
&&&&&&&&perror(&setsockopt&);&&
&&&&&&&&exit(1);&&
&&&&server_addr.sin_family&=&AF_INET;&&&&&&&&&&&
&&&&server_addr.sin_port&=&htons(MYPORT);&&&&&&&
&&&&server_addr.sin_addr.s_addr&=&INADDR_ANY;&&&
&&&&memset(server_addr.sin_zero,&'\0',&sizeof(server_addr.sin_zero));&&
&&&&if&(bind(sock_fd,&(struct&sockaddr&*)&server_addr,&sizeof(server_addr))&==&-1)&{&&
&&&&&&&&perror(&bind&);&&
&&&&&&&&exit(1);&&
&&&&if&(listen(sock_fd,&BACKLOG)&==&-1)&{&&
&&&&&&&&perror(&listen&);&&
&&&&&&&&exit(1);&&
&&&&printf(&listen&port&%d\n&,&MYPORT);&&
&&&&fd_set&&&
&&&&int&&&
&&&&struct&timeval&&&
&&&&conn_amount&=&0;&&
&&&&sin_size&=&sizeof(client_addr);&&
&&&&maxsock&=&sock_&&
&&&&while&(1)&{&&
&&&&&&&&&&
&&&&&&&&FD_ZERO(&fdsr);&&
&&&&&&&&FD_SET(sock_fd,&&fdsr);&&
&&&&&&&&&&
&&&&&&&&tv.tv_sec&=&30;&&
&&&&&&&&tv.tv_usec&=&0;&&
&&&&&&&&&&
&&&&&&&&for&(i&=&0;&i&&&BACKLOG;&i++)&{&&
&&&&&&&&&&&&if&(fd_A[i]&!=&0)&{&&
&&&&&&&&&&&&&&&&FD_SET(fd_A[i],&&fdsr);&&
&&&&&&&&&&&&}&&
&&&&&&&&}&&
&&&&&&&&ret&=&select(maxsock&+&1,&&fdsr,&NULL,&NULL,&&tv);&&
&&&&&&&&if&(ret&&&0)&{&&
&&&&&&&&&&&&perror(&select&);&&
&&&&&&&&&&&&break;&&
&&&&&&&&}&else&if&(ret&==&0)&{&&
&&&&&&&&&&&&printf(&timeout\n&);&&
&&&&&&&&&&&&continue;&&
&&&&&&&&}&&
&&&&&&&&&&
&&&&&&&&for&(i&=&0;&i&&&conn_&i++)&{&&
&&&&&&&&&&&&if&(FD_ISSET(fd_A[i],&&fdsr))&{&&
&&&&&&&&&&&&&&&&ret&=&recv(fd_A[i],&buf,&sizeof(buf),&0);&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&char&str[]&=&&Good,very&nice!\n&;&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&send(fd_A[i],str,sizeof(str)&+&1,&0);&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&if&(ret&&=&0)&{&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&printf(&client[%d]&close\n&,&i);&&
&&&&&&&&&&&&&&&&&&&&close(fd_A[i]);&&
&&&&&&&&&&&&&&&&&&&&FD_CLR(fd_A[i],&&fdsr);&&
&&&&&&&&&&&&&&&&&&&&fd_A[i]&=&0;&&
&&&&&&&&&&&&&&&&}&else&{&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&if&(ret&&&BUF_SIZE)&&
&&&&&&&&&&&&&&&&&&&&&&&&memset(&buf[ret],&'\0',&1);&&
&&&&&&&&&&&&&&&&&&&&printf(&client[%d]&send:%s\n&,&i,&buf);&&
&&&&&&&&&&&&&&&&}&&
&&&&&&&&&&&&}&&
&&&&&&&&}&&
&&&&&&&&&&
&&&&&&&&if&(FD_ISSET(sock_fd,&&fdsr))&{&&
&&&&&&&&&&&&new_fd&=&accept(sock_fd,&(struct&sockaddr&*)&client_addr,&&sin_size);&&
&&&&&&&&&&&&if&(new_fd&&=&0)&{&&
&&&&&&&&&&&&&&&&perror(&accept&);&&
&&&&&&&&&&&&&&&&continue;&&
&&&&&&&&&&&&}&&
&&&&&&&&&&&&&&
&&&&&&&&&&&&if&(conn_amount&&&BACKLOG)&{&&
&&&&&&&&&&&&&&&&fd_A[conn_amount++]&=&new_&&
&&&&&&&&&&&&&&&&printf(&new&connection&client[%d]&%s:%d\n&,&conn_amount,&&
&&&&&&&&&&&&&&&&&&&&&&&&inet_ntoa(client_addr.sin_addr),&ntohs(client_addr.sin_port));&&
&&&&&&&&&&&&&&&&if&(new_fd&&&maxsock)&&
&&&&&&&&&&&&&&&&&&&&maxsock&=&new_&&
&&&&&&&&&&&&}&&
&&&&&&&&&&&&else&{&&
&&&&&&&&&&&&&&&&printf(&max&connections&arrive,&exit\n&);&&
&&&&&&&&&&&&&&&&send(new_fd,&&bye&,&4,&0);&&
&&&&&&&&&&&&&&&&close(new_fd);&&
&&&&&&&&&&&&&&&&break;&&
&&&&&&&&&&&&}&&
&&&&&&&&}&&
&&&&&&&&showclient();&&
&&&&for&(i&=&0;&i&&&BACKLOG;&i++)&{&&
&&&&&&&&if&(fd_A[i]&!=&0)&{&&
&&&&&&&&&&&&close(fd_A[i]);&&
&&&&&&&&}&&
&&&&exit(0);&&
补充部分:
1 基本原理
注:select 原理图,摘自&。
1 数据结构与函数原型
1.1 select
int select(
fd_set *readset,
fd_set *writeset,
fd_set* exceptset,
struct timeval *timeout
select位于:
#include &sys/select.h&
struct timeval位于:
#include &sys/time.h&
返回值
返回对应位仍然为1的fd的总数。
nfds:第一个参数是:最大的文件描述符值+1;readset:可读描述符集合;writeset:可写描述符集合;exceptset:异常描述符;timeout:select 的监听时长,如果这短时间内所监听的 socket 没有事件发生。
1.2 fd_set
1.2.1 清空描述符集合
FD_ZERO(fd_set *)
1.2.2 向描述符集合添加指定描述符
FD_SET(int, fd_set *)
1.2.3 从描述符集合删除指定描述符
FD_CLR(int, fd_set *)
1.2.4 检测指定描述符是否在描述符集合中
FD_ISSET(int, fd_set *)
1.2.5 描述符最大数量
#define FD_SETSIZE 1024
1.3 描述符集合
可读描述符集合中可读的描述符,为1,其他为0;可写也类似。异常描述符集合中有异常等待处理的描述符的值为1,其他为0。
函数原型:
int ioctl(int handle, int cmd,[int *argdx, int argcx]);
#include &sys/ioctl.h&
返回值:
0 - 成功1 - 失败
程序各部分的解释在注释中。
#include &sys/socket.h&
#include &string.h&
#include &sys/time.h&
#include &netinet/in.h&
#include &sys/ioctl.h&
#include &stdlib.h&
#include &errno.h&
#include &stdio.h&
#include &unistd.h&
#define TRUE
#define FALSE 0
int main(int argc, char *argv[])
int i, len, rc, on = TRUE;
int listen_sd, new_sd = 0, max_
char buffer[80];
int close_conn, end_server = FALSE;
struct sockaddr_in server_
struct fd_set master_set, working_
listen_sd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_sd & 0)
perror(&socket() failed&);
// Set socket options
rc = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));
if (rc & 0)
perror(&setsockopt() failed&);
close(listen_sd);
// Set IO control
rc = ioctl(listen_sd, FIONBIO, (char *) &on);
if (rc & 0)
perror(&ioctl() failed&);
close(listen_sd);
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(atoi(argv[1]));
rc = bind(listen_sd, (struct sockaddr *) &server_addr, sizeof(server_addr));
if (rc & 0)
perror(&bind() failed\n&);
close(listen_sd);
rc = listen(listen_sd, 32);
if (rc & 0)
perror(&listen() failed\n&);
close(listen_sd);
// Intialize sd set
FD_ZERO(&master_set);
max_sd = listen_
FD_SET(listen_sd, &master_set);
timeout.tv_sec = 3 * 60;
timeout.tv_usec = 0;
// Copy master_set into working_set
memcpy(&working_set, &master_set, sizeof(master_set));
printf(&Waiting on select()...\n&);
rc = select(max_sd + 1, &working_set, NULL, NULL, &timeout);
if (rc & 0)
select() failed\n&);
if (rc == 0)
select() timed out. End program.\n&);
desc_ready = // number of sds ready in working_set
// Check each sd in working_set
for (i = 0; i &= max_sd && desc_ready & 0; ++i)
// Check to see if this sd is ready
if (FD_ISSET(i, &working_set))
// Check to see if this is the listening sd
if (i == listen_sd)
Listeing socket is readable\n&);
new_sd = accept(listen_sd, NULL, NULL);
// Nothing to be accepted
if (new_sd & 0)
// All have been accepted
if (errno != EWOULDBLOCK)
accept() failed\n&);
end_server = TRUE;
// Insert new_sd into master_set
New incoming connection - %d\n&, new_sd);
FD_SET(new_sd, &master_set);
if (new_sd & max_sd)
max_sd = new_
while (new_sd != -1);
// This is not the listening sd
close_conn = FALSE;
Descriptor %d is avaliable\n&, i);
rc = recv(i, buffer, sizeof(buffer), 0);
// Receive data on sd &i&, until failure occurs
if (rc & 0)
// Normal failure
if (errno != EWOULDBLOCK)
recv() failed\n&);
close_conn = TRUE;
// The connection has been closed by the client
if (rc == 0)
Connection closed\n&);
close_conn = TRUE;
/* Receiving data succeeded and echo it back
the to client */
%d bytes received\n&, len);
rc = send(i, buffer, len, 0);
if (rc & 0)
send() failed&);
close_conn = TRUE;
while (TRUE);
// If unknown failure occured
if (close_conn)
// Close the sd and remove it from master_set
FD_CLR(i, &master_set);
// If this is the max sd
if (i == max_sd)
// Find the max sd in master_set now
while (FD_ISSET(max_sd, &master_set) == FALSE)
} // End of if (i == max_sd)
} // End of if (close_conn)
while (end_server == FALSE);
/* Close each sd in master_set */
for (i = 0; i & max_ ++i)
if (FD_ISSET(i, &master_set))
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:4000次
排名:千里之外
(1)(3)(1)(1)(1)

我要回帖

更多关于 中土世界2战争之影 的文章

 

随机推荐