tc的ulog文件解析及复制协议

1. 打开ulog文件

 2. 读取ulog文件

 

 3. 复制协议

参看: ttserver.c:do_slave

打开连接:

tcreplopen(repl, arg->host, arg->port, arg->rts + 1, sid)

读取信息:

tcreplread(repl, &rsiz, &rts, &rsid)

 

4. 其它

/* Receive data by a socket. */

bool ttsockrecv(TTSOCK *sock, char *buf, int size){

 

/* Receive one byte by a socket. */

int ttsockgetc(TTSOCK *sock){

 

/* Receive one line by a socket. */

bool ttsockgets(TTSOCK *sock, char *buf, int size){

 

/* Receive an 32-bit integer by a socket. */

uint32_t ttsockgetint32(TTSOCK *sock){

 

各命令的记录格式可参看:  tculogadbredo(…)

关于rsyslog的学习

从配置文件学起:

关于配置文件

  1. 配置文件的解析参看文件 runtime/rsconf.c
  2. $ActionExecOnlyWhenPreviousIsSuspended
关于配置文件的说明: http://www.rsyslog.com/doc/rsyslog_conf.html

关于模块

http://www.rsyslog.com/doc/rsyslog_conf_modules.html

 

问题

  1. 关于 QueueTimeoutActionCompletion 的理解

摘自官方文档

Discarding Messages

An interesting application is with disk-assisted queues: if the discard watermark is set lower than the high watermark, message discarding will start before the queue becomes disk-assisted. This may be a good thing if you would like to switch to disk-assisted mode only in cases where it is absolutely unavoidable and you prefer to discard less important messages first.

翻译:

关于使用磁盘辅助队列的一个有意思的应用方式是: 如果“丢弃水位”被设置的低于“高水位”,将在启用磁盘之前开始丢弃消息。如果你情愿丢弃一些不重要的消息,也不愿意使用磁盘的话,这是一个不错的选择。

摘自: http://www.rsyslog.com/doc/queues.html

命名惯例

Output modules, and only output modules, should start with a file name of “om” (e.g. “omfile.c”, “omshell.c”). Similarly, input modules will use “im” and filter modules “fm”. The third character shall not be a hyphen.

摘自: http://www.rsyslog.com/doc/modules.html

 

 

关于数据报与字节流的理解

(1)定义差别[1]

数据报是网络传输的数据的基本单元,包含一个报头和数据本身,其中报头描述了数据的目的地以及和其它数据之间的关系。同一报文的不同分组可以由不同的传输路径通过通信子网。UDP基于数据报
字节流方式指的是仅把传输中的报文看作是一个字节序列,在字节流服务中,由于没有报文边界,用户进程在某一时刻可以读或写任意数量的字节。 TCP基于字节流

(2)接收方式

TCP方式:

 

UDP方式:

注:If the datagram or message is larger than the buffer specified, the buffer is filled with the
first part of the datagram, and recv generates the error WSAEMSGSIZE. For unreliable protocols
(for example, UDP) the excess data is lost; for reliable protocols, the data is retained by the
service provider until it is successfully read by calling recv with a large enough buffer.

 

(3)处理大数据包或本地读出缓存小存在的问题

Posix系列的recv、recvfrom、read函数均无法得到数据包被截断的错误消息,只有recvmsg可以得到该消息。 ssize_t recvmsg(int socket, struct msghdr *message, int flags); 如果message->msg_flags & MSG_TRUNC为真,则表示数据包被截断。超出部分被丢弃。但也有例外,Solaris并不设置MSG_TRUNC,直接丢弃超出部分。 SVR4系统不丢弃超出部分,在后续的读操作中会获取超出部分。 Windows下的recv、recvfrom、WSARecv、WSARecvFrom会返回-1,并设置Last Error为WSAEMSGSIZE。另外,WSARecvEx函数则是专门用于这方面的一个函数。 int PASCAL FAR WSARecvEx(SOCKET s, char* buf, int len, int* flags); 当*flags & MSG_PARTIAL为真实,表示数据包被截断 Windows下所有超出的数据包都会被丢弃

(4)疑问

recvfrom 与 recv均可以用在基于链接的或非链接的socket,两者就是接口不同吗?

这两个函数的区别仅仅在于,recvfrom会记录对方的socket地址,recvfrom有一个容易出错的地方,就是关于from地址的长度,在调用时这个长度必须是结构体struct sockaddr的长度,因为在recvfrom的实现中将会用到这个值。Recv/send中的flag如果是0,那么这两个函数等同于read/write. 需要注意的是,系统的socket缓冲区中并没有对收到的数据作字符串式的结尾处理,所以分析报文需要时需要用到recv/recvfrom返回的实际读取长度。

参考:

  1. UDP数据包截断 http://www.javaeye.com/wiki/topic/248817
  2. http://www.cppblog.com/wangfeng2500/articles/150758.html

OSI 参考模块数据单元

数据报 [Datagram]

通过网络传输的数据的基本单元,包含一个报头(header)和数据本身,其中报头描述了数据的目的地以及和其它数据之间的关系。一个Datagram可能被压缩成一个或几个packets,在数据链路层中传输。

数据包 [Packet]

封装的基本单元,它穿越网络层和数据链路层的分解面。通常一个Packet映射成一个frame,但也有例外:即当数据链路层执行拆分或将几个Packet合成一个frame的时候。

二层的PDU叫做Frame;
IP的叫做Packet;
TCP的叫做Segment;
UDP的叫做Datagram。

OSI参考模型的各层传输的数据和控制信息具有多种格式,常用的信息格式包括帧、数据包、数据报、段、消息、元素和数据单元。信息交换发生在对等OSI层之间,在源端机中每一层把控制信息附加到数据中,而目的机器的每一层则对接收到的信息进行分析,并从数据中移去控制信息,下面是各信息单元的说明:
帧(frame)是一种信息单位,它的起始点和目的点都是数据链路层。
数据包(packet)也是一种信息单位,它的起始和目的地是网络层。
数据报(datagram)通常是指起始点和目的地都使用无连接网络服务的的网络层的信息单元。
段(segment)通常是指起始点和目的地都是传输层的信息单元。
消息(message)是指起始点和目的地都在网络层以上(经常在应用层)的信息单元。
元素(cell)是一种固定长度的信息,它的起始点和目的地都是数据链路层。元素通常用于异步传输模式(ATM)和交换多兆位数据服务(SMDS)网络等交换环境。
数据单元(data unit)指许多信息单元。常用的数据单元有服务数据单元(SDU)、协议数据单元(PDU)。SDU是在同一机器上的两层之间传送信息。PDU是发送机器上每层的信息发送到接收机器上的相应层(同等层间交流用的)。

Unix Domain Socket的一些理解

1. unix域的数据报服务是否可靠

man unix 手册即可看到,unix domain socket 的数据报既不会丢失也不会乱序 (据我所知,在linux下的确是这样)。不过最新版本的内核,仍然又提供了一个保证次序的类型 “ kernel 2.6.4 SOCK_SEQPACKET ”。

2. STREAM 和 DGRAM 的主要区别

既然数据报不丢失也可靠,那不是和 STREAM 很类似么?我理解也确实是这样,而且我觉得 DGRAM 相对还要好一些,因为发送的数据可以带边界。二者另外的区别在于收发时的数据量不一样,基于 STREAM 的套接字,send 可以传入超过 SO_SNDBUF 长的数据,recv 时同 TCP 类似会存在数据粘连。

采用阻塞方式使用API,在unix domain socket 下调用 sendto 时,如果缓冲队列已满,会阻塞。而UDP因为不是可靠的,无法感知对端的情况,即使对端没有及时收取数据,基本上sendto都能立即返回成功(如果发端疯狂sendto就另当别论,因为过快地调用sendto在慢速网络的环境下,可能撑爆套接字的缓冲区,导致sendto阻塞)。

3. SO_SNDBUF 和 SO_REVBUF

对于 unix domain socket,设置 SO_SNDBUF 会影响 sendto 最大的报文长度,但是任何针对 SO_RCVBUF 的设置都是无效的 。实际上 unix domain socket 的数据报还是得将数据放入内核所申请的内存块里面,再由另一个进程通过 recvfrom 从内核读取,因此具体可以发送的数据报长度受限于内核的 slab 策略 。在 linux 平台下,早先版本(如 2.6.2)可发送最大数据报长度约为 128 k ,新版本的内核支持更大的长度。

4. 使用 DGRAM 时,缓冲队列的长度

有几个因素会影响缓冲队列的长度,一个是上面提到的 slab 策略,另一个则是系统的内核参数 /proc/sys/net/unix/max_dgram_qlen。缓冲队列长度是这二者共同决定的。

如 max_dgram_qlen 默认为 10,在数据报较小时(如1k),先挂起接收数据的进程后,仍可以 sendto 10 次并顺利返回;

但是如果数据报较大(如120k)时,就要看 slab “size-131072” 的 limit 了。

5. 使用 unix domain socket 进行进程间通信 vs 其他方式

  • 需要先确定操作系统类型,以及其所对应的最大 DGRAM 长度,如果有需要传送超过该长度的数据报,建议拆分成几个发送,接收后组装即可(不会乱序,个人觉得这样做比用 STREAM 再切包方便得多)
  • 同管道相比,unix 域的数据报不但可以维持数据的边界,还不会碰到在写入管道时的原子性问题。
  • 同共享内存相比,不能独立于进程缓存大量数据,但是却避免了同步互斥的考量。
  • 同普通 socket 相比,开销相对较小(不用计算报头),DGRAM 的报文长度可以大于 64k,不过不能像普通 socket 那样将进程切换到不同机器 。

参考资料:

http://www.cnblogs.com/skynet/archive/2010/12/04/1881236.html

http://hi.baidu.com/studyarea/blog/item/b007f4450a2a9e38879473ca.html

Unix Domain Socket使用遇到的一个问题

转自: http://www.cnblogs.com/skynet/archive/2010/12/04/1881236.html

(这里详细描述了unix domain socket使用过程中的一个问题)

 

1、Unix domain socket简介

unix域协议并不是一个实际的协议族,而是在单个主机上执行客户/服务器通信的一种方法,所用API于在不同主机上执行客户/服务器通信所有的API(套接字API,如AF_INET、AF_INET6等类型的API)相同。unix域协议可以视为是进程之间本地通信IPC的一种。

unix域提供两类套接口:字节流套接口(类似TCP)和数据报套接口(类似UDP)。使用Unix域套接口的理由有三:

  • Unix域套接口往往比位于同一主机的TCP套接口快出一倍。
  • Unix域套接口可用于在同一主机上的不同进程之间传递描述字。
  • Unix域套接口把客户的凭证(用户ID和用户组ID)提供给服务器,从而实现能够提供额外的安全检查措施。

Unix域中用域标识客户和服务器的协议地址是普通文件系统中的路径名(类比:IPv4协议的地址由一个32位地址和一个16位端口号构成,IPv6协议的地址由一个128位地址和16位端口号构成。)。

2、问题描述

简单介绍了Unix域套接口之后,进入主题——描述我碰到的问题。由于unix域套接口用于本机间进程通信比网络套接口效率高,因为它是不经过协议栈的!在项目中选择了unix域的数据报套接口。在使用过程中碰到了如下,问题:发送<128K的消息时,客户、进程可以正常收发消息;发送>=128K的消息时,发送端(sendto)返回ENOBUFS的错误。

服务器的代码如下:

客户端的代码如下:

 

3、可能碰到的另外一个问题

如果你没有设置足够大的发送缓冲区大小,你很有可能碰到EMSGSIZE的错误!因为应用程序写了一个大于套机口发送缓冲区大小的数据报,内核报EMSGSIZE错误。如下图:

(注意:UDP套接口有发送缓冲区的大小,并且可以通过SO_SNDBUF套接口选项修改。不过它仅仅是写到套接口的UDP数据报的大小,因为UDP是不可靠的,它不必保存应用进程的数据拷贝,因此无需一个真正的发送缓冲区。)上面的代码已经设置了足够大的发送缓冲区大小。

4、我的尝试

在sendto发送>=128K大小的消息时,返回ENOBUFS错误。

  • 我怀疑是否是sendto()的原因,我改用sendmsg(),未果还是返回这个错误。
  • 有人说是:“发送消息太频繁,间隔太短”。其实项目中发送消息根本就不频繁,背着死马当活马医,未果还是返回这个错误。
  • 尝试修改/proc/sys/net/core下面的各种相关选项,如
    未果,还是返回这个错误。(其它路径下的相关选项也试了,不行)
  • ?我无从下手了,不知道128K的这个限制在哪?既然“No buffer space available”,我怎样给他空间?

5、最终原因及解决办法(都是内核惹得祸!!)

至此,我实在没有办法了,不知道如何解决!但是从错误ENOBUFS的说明:
ENOBUFS means there is no sufficient memory available and the system(kernel)  can not allocate any more. Application will usually retry the operation when it detects this error from a system call since it indicates there is a transient resource shortage. It is the Operating system that refuses the resource request from the listener. The virtual memory allocation routine of the OS will determine if a swap can be made to disk of a real memory segment thereby allowing the listener access to some more real memory.
可以看出一些端倪,这肯定跟内存分配有关!而且限制在分配128K就失败!利用Socket进行进程间的通信,需要经过Linux内核:进程1将数据写到内核,进程2从内核读取数据。内核必须申请一个空间来存放数据包!实际上,socket发送数据包时,需要从slab中申请一块cache存放数据包。
  • 在2.6.21内核中(这就是我们公司服务器的内核版本),slab分配器最大支持的size为128K(详情可见/proc/slabinfo)。
  • 在2.6.31内核中,slab分配器最大支持的size大小为32M。
所以2.6.21内核上,发送大于128K的数据包时,Kmalloc()会失败,并返回no buffer的错误。建议:对于本地进程通信,可以使用其它的IPC方式,进行数据通信,如shm、pipe等。
找出了原因,可以采用以下方式来解决该问题:
  • 升级内核,或修改内核的这个限制。
  • 改用unix 域udp套接口为unix域tcp套接口(最终我们采用的方式)。
  • 改用其它的IPC方式(这个涉及到太多的修改,故我们放弃使用)。
附/proc/slabinfo 信息:size-131072即128K的限制!

我在Ubuntu 10.10上测试,不会报ENOBUFS的错误。内核版本为:

/proc/slabinfo的信息如下,跟上面的有些差异:
kmalloc的最大限制是8192K,故我们运行上述程序没有问题!
原来都是内核惹得祸阿,害我困惑那么久!!!baidu和google都没有找到原因,因此分享此文,以警惕后者。

网络编程知识点

转自: http://blog.csdn.net/wlh_flame/article/details/6381780

(评论:虽然问题不大,但是新手基本会遇到这些问题的,所以还很重要)

 

——记录一些小问题,陷阱

1. 调用bind时,如果地址是0(就是INADDR_ANY那个宏),就绑定本地所有IP,如果端口是0,就随机选择一个可用的端口(想要知道具体端口,可以调用getsockname查看)

2. send recv 与 read write 的区别主要在于:send 和 recv 可以设置一些 flag,而 read 和 write 则没有

3. 阻塞与非阻塞:调用 API 时是否需要等待完成时才返回

4. send/sendto 的一般返回情况:

非阻塞或超时——根据当前缓冲区空闲长度,尽力向套接字缓冲区拷贝,完成了多少算多少,立返回

阻塞——完成所有数据的拷贝,才返回。如果现在空闲区大小不够,会等待至空闲区够了并拷贝,完成拷贝后返回

tcp 是数据流,所以 send 的数据可以很大,而不会返回消息过长的错误;

udp 因为仅组装成一个数据报,不能够分开多次发送,所以如果发送的数据量大于缓冲区长度,会立即返回消息过长的错误。

非阻塞的发送可以是套接字级别的,通过 setsockopt 设置;也可以是消息级别的,通过 send 调用时的 MSG_DONTWAIT 标记

— 可以用异步方式,将套接字设置为非阻塞,但是需要注意检查 send 函数的返回值,验证 recv 收到的包的完整性

5. udp 下也可以使用 connect,同 tcp 相比,并没有握手过程,只是设定了套接字数据结构里面的远端地址部分

6. 在 tcp 套接字被 shutdown 后,调用读写该套接字的 API 除了返回 EPIPE 错误外,还会产生 SIGPIPE 信号(默认操作是退出进程)。可以在调用 API 时,通过 MSG_NOSIGNAL 标记来告知内核,无需发出这一信号。

7. udp 收包时,如果缓冲区大小比包长要小,那其行为是未定义的,建议最好一次收个够

8. tcp 发包时,担心因为包太小无法即时发送出去的话,可以设置 TCP_NODELAY 套接字选项

9. udp 发包过快会造成本地或远端被“淹没”。考虑一个 udp 服务器,如果接收缓冲区满了,此时还有 udp 数据到达,则协议栈会丢弃新到达的数据。(仅从机器负载去看,难以断定是否会“淹没”,只能估算;淹没发生时,进程通常忙于干其他事情或被阻塞,因此从可控的角度来讲,只好尽量降低 CPU 负载、尽量采用异步)

udp 丢包的几种情况:网络导致,缓冲区长度不够长导致(rmem_max、SOL_SNDBUF),缓冲区已满

10. tcp connect 时,默认超时因系统不同而不同,一般都要那么几分钟,如果想要主动控制这个超时,有几种方法:修改内核参数、使用异步的 select 和 epoll 查看是否返回套接字可写,如果是 linux 环境,那么 SOL_SNDTIMEO 选项也能起作用。

11. linux下多个子进程可以竞争accept同一个套接字,进程/线程池基本就是这样一种思路,先fork几个再让它们都竞争accept。监视客户端的数量,可以动态地增加、减少进程数。

12. 异步connect时,如果超时会返回一个出错事件,错误码被置为EINPROGRESS

13. 编写一个完善的服务器,要考虑:常见信号是否已经捕获并处理(如SIGSEGV、SIGCHLD、SIGPIPE、SIGTERM、SIGINT等),系统API的返回值是否进行了合理的检查,日志体系是否完善。如果使用了epoll,还要对错误类事件统一处理。

14. 对TCP的情况,如果使用KEEPALIVE选项,协议栈会探测链接的对端是否有响应,如果没有的话会返回套接字可读,receive返回错误。

关于北京车辆的两个网站

1. http://www.bjjtgl.gov.cn/   北京市公安局公安交通管理局 (车辆违规记录查询)

2. http://www.bjhjyd.gov.cn/  北京市小客车指标调控管理信息系统  (申请摇号)

3. http://www.bjhjyd.gov.cn/sblc/  申报流程

 

截至2012年7月底,全市机动车保有量511.6万辆,驾驶员714.5万人;(摘自: http://www.bjjtgl.gov.cn/publish/portal0/

 

截止至2012年8月8日24:00,小客车指标申请累计收到个人小客车配置指标申请和确认延期的共1078029个,有26045家企事业等单位申请小客车配置指标44180个。(摘自: http://www.bjhjyd.gov.cn/jggb/201288/1344416310954_1.html

 

其它信息:

 

Apache中PHP脚本的默认的content-type

通过Apache 访问一个PHP文件,默认的content-type为 text/html , 如果通过PHP输入其他类型的内容需要通过header来设置,那么默认的content-type 是在什么地方做的呢?

 

 

 

关于vim使用

从删除空行说起:

命令:

这里面包含三部分:

1: g

2: /^$/

3: d

关于 :g 的使用参看:

global 用于重复执行一条命令,  ‘d’ 就是delete,相当于选择模式匹配的部分,然后执行一个d命令,也可以是:

如下命令是怎么解释的呢:

‘s’ 是一个替换命令,后面是其参数,可以适当选择合适的分隔符,如把所有的 /data1 替换为 /data2:

这里使用 ‘/’ 做分隔符显然不太合适,使用 # 就省得对 ‘/’  做转义了