分类目录归档:LINUX C & ARM & C51

STM8 读取 UID

UID

UID即Unique ID,STM8S105提供了96BIT的全球唯一ID,可以用于加密,也可以用于板子的ID,像我的应用,就是用在了给箱子一个全球唯一的ID,这样就便于联网了。

用UID的时候,请参考英文手册,不知道为什么,中文版的是没有UID这方面的介绍的。那么我们就来学习一下UID把,官方给的应用如下:

•For use as serial numbers

•For use as security keys to increase the code security in the program memory while using and combining this unique ID with software cryptograhic primitives and protocols before programming the internal memory.

•To activate secure boot processes

其地址如下:

 1473251352-3985-30

1-2 byte为晶圆上x轴位置
3-4 byte为晶圆上y轴位置
5   byte为晶圆号码
6-12 byte是Lot number.

实际上一开始的时候,我也对UID的读取是相当的疑惑,但是看了这个地址后,其实就是直接读取地址上的数据就可以了。程序如下:

void get_id(void)

{

u8 i;

u16 addr;

u8 uid1[12];

addr=0x48CD;

for(i=0;i<12;i++)

{

uid1[i]=*(u8*)addr++;

putchar(uid1[i]);

}

}

怎么样,简单把,还有另外一个方法,在网上搜到的,也分享给大家把,

__no_init const union { //either the struct or a string

struct { //nameless struct

unsigned short X_coordinate; //X-coordinate on the wafter

unsigned short Y_coordinate; //Y-coordinate on the wafer

unsigned char Wafer_Number; //wafer number

unsigned char Lot_Number[7]; //lot number

} ;

unsigned char str[12]; //or the string

} U_ID @ 0x48cd; //u_id typ

J-link V8固件升级记

好久没为电子工程事业尽份力了!今天也稍微努把力!写写我是如何升级J-link的固件的吧!

111

 

 

 

 

 

 

J-link是什么?晕,不是电子工程师的退散吧!这是现在比较流行的arm调试工具!我手上是那个大家都比较喜闻乐见的V8版本!盗版吗!大家懂的!50元入手的!没有软件升级与维护的!说不准哪天!升级软件就封杀了!如果固件没法更新就基本一块砖!砸人防身都可以哦!
222

 

 

 

 

 

首先在通电情况下,短接a!然后拔下usb 接着短接b,然后插入usb 10秒,然后拔下usb。最后从新上电插入usb!于是你的电脑里面就有了一个无法识别新设备!

333

 

 

 

 

 

 

 

 

去atmel官网下载最新版本的SAM-BA v2.12软件,你就可以正确识别硬件为一个usb转串口设备了!

http://ishare.iask.sina.com.cn/f/34214872.html

双击运行SAM-BA v2.12

444

 

 

 

 
设置你的设备端口号,还有芯片型号!之后点击连接!

666

 

 

 

 

 

 

 

进入固件刷写窗口!选择好新固件的文件地址!然后点send file

http://ishare.iask.sina.com.cn/f/34231756.html

777

 

 

 

 

 

 
提示是否加密!选择yes!

888

 

 

 

 

 

 
烧录进行中~~~~

999

 

 

 

 

 

 
再次提示是否要加密,选择no!之后退出程序!

拔掉J-link,然后从新插入usb!

1111

 

 

 

 

 

 

 

 

又会有新设备,这个时候要去下载安装J-Link ARM V4.40驱动就有了!

注意一定要是J-Link ARM V4.40 之后的版本都会封杀你的破解!

http://download.csdn.net/detail/wm20031015/3926860  

2222

 

 

 

 

 
运行J-Link ARM V4.40提示升级,选择yes

5555

 

 

 

 

 

 

6666

 

 

 

 
提示升级成功!

从新插拔一下J-link!好了你的J-link V8又复活了!

双击J-Link ARM V4.40 程序正常运行了!

8888

 

 

 

 

 

 

^_^,我能给的也就这么多了!如果还有什么问题,或者说新的4.5.0之后的版本需要破解的话,估计就又得等等了!不过至少现在J-link V8 又可以欢快的陪我们工作一阵子了!

 

install_at91-isp

jlnk_bin_烧录

STM32 的加密实现

目的:对运行于STM32的嵌入式代码程序进行加密

编译环境:IAR Embedded System for ARM5.5

一.STM32Flash组织

1460007975-5260-

STM32的Flash包括主存储器(HD版本,512KB)+信息块。信息块包括2KB的系统存储器(用于系统自举启动代码)和16字节的选项字节(8个字节数据+8个字节数据的反码)。

二、STM32读保护

STM32读保护是通过设置RDP选项字节,然后在系统重新复位加载了新的RDP选项字节后启动的。当保护字节被写入相应的值以后:

●通过从内置SRAM或FSMC执行代码访问主闪存存储器的操作,通过DMA1、DMA2、JTAG、SWV(串行线观察器)、SWD(串行线调试)、ETM和边界扫描方式对闪存的访问都将被禁止。

●只允许从用户代码中对主闪存存储器的读操作(以非调试方式从主闪存存储器启动)。

●第0~3页(小容量和中容量产品),或第0~1页(大容量和互联型产品)被自动加上了写保护,其它部分的存储器可以通过在主闪存存储器中执行的代码进行编程(实现IAP或数据存储等功能),但不允许在调试模式下或在从内部SRAM启动后执行写或擦除操作(整片擦除除外)。

●所有通过JTAG/SWD向内置SRAM装载代码并执行代码的功能依然有效,亦可以通过JTAG/SWD从内置SRAM启动,这个功能可以用来解除读保护。当读保护的选项字节转变为存储器未保护的数值时,将会执行整片擦除过程。

●可以使用系统启动程序解除读保护(此时只需执行系统复位即可重新加载选项字节),芯片自动擦除Flash所有内容。

三.STM32的加密

1.使用系统启动程序STM32 Flash Loader demonstrator将Flash设置为读保护。

所有以调试工具、内置SRAM或FSMC执行代码等方式对主存储器访问的操作将被禁止,只允许用户代码对主Flash存储器的读操作和编程操作(除了Flash开始的4KB区域不能编程)。用户代码允许自主编程可以实现IAP或者数据存储等功能。

这样破解者将不能用调试工具、内置SRAM或者FSMC执行代码等方式读出Flash中的代码。破解者也不能使用系统启动程序读取代码,因为要解除读保护,将执行整个芯片的擦除操作。

2.主程序中使用设备ID保护

即使将Flash设置为读保护,破解者也可以通过IAP下载自己的一段小程序,从而读出Flash中的内容。因此,还需要利用设备的唯一ID进行加密保护。在主程序中,加入对设备唯一ID的检测,这样即使破解者读出了芯片中的二进制码,也不能用这个二进制码去复制新的器件。具体实现方法:

(1)在应用程序中定义1个(32位甚至更多)const变量,变量值全为0xFF。每次启动程序时,检查const变量值如果全为0xFF,就读器件的唯一ID,通过Flash编程写入该const变量中(因为全是0xFF,所以可以编程写入)。

(2)在程序中多个地方检查const变量,如果变量值不为0xFF并且与设备ID不一致,就执行与功能无关代码(比如自擦除)。

这样,即使破解者读出了芯片中的二进制码,因为这份二进制码包含了设备唯一ID,具有唯一性,所以不能复制到其他芯片中。

为了避免破解者利用反汇编,根据芯片ID数据在二进制文件中查找对应相同数据的位置从而破解,可以将ID拆散成不同的组合,并且写到不同且不连续的地方。更进一步,可在程序中检测多份这样的分散ID,以增加反汇编的难度。或者将CPUID进行加密,Flash中存储加密后的结果。

四.程序加密的实现

 

[cpp] view plaincopy
01.//加密后的CPUID
02.volatile const static uint32 CPUIDEncrypt = 0xFFFFFFFF;
03.
04.//写入加密数据
05.void WriteEncrypt(void)
06.{
07.    //第一次烧写:将UID写入到Flash中
08.    if(CPUIDEncrypt==0xFFFFFFFF)
09.   {
10.        uint32_t CpuID[3];
11.        //获取CPU唯一的ID
12.        CpuID[0]=*(vu32*)(UID_BASE);
13.        CpuID[1]=*(vu32*)(UID_BASE+4);
14.        CpuID[2]=*(vu32*)(UID_BASE+8);
15.
16.        //加密算法,很简单的加密算法
17.        uint32_t EncryptCode=(CpuID[0]>>3)+(CpuID[1]>>1)+(CpuID[2]>>2);
18.        FLASH_Unlock();
19.        FLASH_ClearFlag(FLASH_FLAG_BSY|FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR);
20.        FLASH_ProgramWord((uint32_t)&CPUIDEncrypt, EncryptCode);
21.        FLASH_Lock();
22.    }
23.}
24.//判断加密
25.bool JudgeEncrypt(void)
26.{
27.    uint32_t CpuID[4];
28.    //获取CPU唯一的ID
29.    CpuID[0]=*(vu32*)(UID_BASE);
30.    CpuID[1]=*(vu32*)(UID_BASE+4);
31.    CpuID[2]=*(vu32*)(UID_BASE+8);
32.    //加密算法,很简单的加密算法
33.    CpuID[3]=(CpuID[0]>>3)+(CpuID[1]>>1)+(CpuID[2]>>2);
34.    //检查Flash中的UID是否合法
35.    return (CPUIDEncrypt == CpuID[3]);
36.}
1、将写入加密数据和判断加密两个功能分开。写入加密在PrsCtrlTask开始的地方;而判断加密分布到程序的各个角落。

2、非常重要的是CPUID加密值的定义一定要加“volatile”类型:

volatile const static uint32 CPUIDEncrypt = 0xFFFFFFFF;

否则按速度优化编译,在判断加密值,不会重新读取加密值,导致判断出错。

3、在工程选项Options->Debugger->Download中选择: use flash loader

否则主程序中对Flash编程将不成功。

参考资料:

STM32F10x微控制器参考手册(2009年12月第10版).pdf

STM32单片机 如何选择

自从ARM公司2007年首推出Cortex内核,ST凭借基于ARM CORTEX-M3内核的STM32F1,无疑成为了最大的赢家之一。特别是STM32F103系列,更是成为市场上最通用的MCU系列之一。

不过在Cortex-M3内核出来了7年之际,在我看来Cortex-M3内核已经不能算是性价比最高的MCU内核了。反而Cortex-M0+和Cortex-M4优化越来越好。鉴于我个人对ST MCU比较熟悉,我在这里介绍几款比STM32F103系列性价比更高的MCU系列。

STM32F030—-ARM Cortex-M0内核。最高主频48MHZ,特别是STM32F030F4,16K FLASH,4K RAM , TSSOP20封装。价格在3块钱左右。

STM32F042—-同样Cortex-M0内核 。14年初推出的芯片,号称带USB,CAN总线的最便宜的MCU。可以和STM32F103系列 完全 PIN TO PIN 。适用于需要USB功能的小型电脑周边产品。

STM32L053—-Cortex-M0+内核,14年推出。STM32L152系列的芯片我测过功耗,并没有我想象中的如意,比STM32F103略低,但比起市场上其他的低功耗MCU,并没有太明显的优势。但L053确实做得更好,可以详见我的实测笔记http://bbs.21ic.com/icview-835590-1-1.html 。主频32MHZ,最大FLASH 64kb.适用于低功耗要求苛刻的小型产品应用。跟STM32F103 PIN TO PIN

STM32F411–STM32系列中Cortex-M4内核中比较通用还是STM32F407系列,最高主频180MHZ。但这块STM32F401的特点在于其低功耗。运行功耗100uA/mhz,比32L053还略低。但由于是Cortex-M4内核,更方面功能会更强(最高主频84MHZ , FLASH 512kb),十分适用于智能手环等可穿戴类产品。

STM32F303—-各方面跟STM32F103一模一样,除了多了一个浮点运算,对于运算较多,很多Sensor数据处理的产品,可以考虑。

uclibc,eglibc,glibc,Musl-libc之间的区别和联系

1.Glibc glibc = GNU C Library 是GNU项(GNU Project)目,所实现的 C语言标准库(C standard library)。 目前,常见的桌面和服务器中的GNU/Linux类的系统中,都是用的这套C语言标准库。 其实现了常见的C库的函数,支持很多种系统平台,功能很全,但是也相对比较臃肿和庞大。

2.uClibc 一个小型的C语言标准库,主要用于嵌入式。 其最开始设计用于uClinux(注:uClinux不支持MMU),因此比较适用于微处理器中。 对应的,此处的u意思是μ,Micro,微小的意思。 uClibc的特点: (1)uClibc比glibc要小很多。 (2)uClibc是独立的,为了应用于嵌入式系统中,完全重新实现出来的。和glibc在源码结构和二进制上,都不兼容。

3.EGLIBC EGLIBC = Embedded GLIBC EGLIBC是,(后来)glibc的原创作组织FSF所(新)推出的,glibc的一种变体,目的在于将glibc用于嵌入式系统。 EGLIBC的目标是: (1)保持源码和二进制级别的兼容于Glibc 源代码架构和ABI层面兼容 如果真正实现了这个目标,那意味着,你之前用glibc编译的程序,可以直接用eglibc替换,而不需要重新编译。 这样就可以复用之前的很多的程序了。 (2)降低(内存)资源占用/消耗 (3)使更多的模块为可配置的(以实现按需裁剪不需要的模块) (4)提高对于交叉编译(cross-compilation)和交叉测试(cross-testing)的支持 Eglibc的最主要特点就是可配置,这样对于嵌入式系统中,你所不需要的模块,比如NIS,locale等,就可以裁剪掉,不把其编译到库中,使得降低生成的库的大小了。 更多特点,可以去看:Eglibc的特点 【glibc, uClibc, Elibc的渊源/历史/区别/联系】 1. 写程序,需要用到很多c语言的库函数。所有的库函数加起来,就是对应的C语言(标准)函数库。 2. 目前在普通GNU/Linux系统中所用的C语言标准库,叫做glibc。其功能很全,函数很多,但是代码太多,编译出来的函数库的大小也很大,即资源占用也很多。 3. 而嵌入式系统中,也需要C语言写代码实现特定功能,也需要用到C语言函数库,但是由于嵌入式系统中,一般资源比较有限,所以不适合直接使用(太占用资源的)gLibc。 4. 所以有人就又(没有参考glibc,而是从头开始,)重新实现了一个用于嵌入式系统中的,代码量不是很大的,资源占用相对较少的,C语言函数库,叫做uClibc。并且,uClibc不支持MMU(内存管理单元)。 5. 而后来,glibc的开发者,又推出个Embedded glibc,简称eglibc,其主要目的也是将glibc用于嵌入式领域。 相应最大的改动就在于,把更多的库函数,改为可配置的,这样,如果你的嵌入式系统中不需要某些函数,就可以裁剪掉,不把该函数编译到你的eglibc库中,使得最终生成的eglibc库的大小变小,最终符合你的嵌入式系统的要求(不能超过一定的大小),这样,就实现了,把glibc引用于嵌入式系统中的目的了。 可以简单的理解为: glibc,uClibc,eglibc都是C语言函数库: 1. uClibc是嵌入式系统中用的,glibc是桌面系统用的 2. eglibc也是嵌入式系统中用的,是glibc的嵌入式版本,和glibc在源码和二进制上兼容。

4. Musl-libc  C语言标准库Musl-libc项目发布了1.0版。Musl是一个轻量级的C标准库,设计作为GNU C library (glibc)、 uClibc或Android Bionic的替代用于嵌入式操作系统和移动设备。它遵循POSIX 2008规格和 C99 标准,采用MIT许可证授权,使用Musl的Linux发行版和项目包括sabotage,bootstrap-linux,LightCube OS等等。

目前openwrt 15.05默认使用Musl-libc了。。。bug很多呀 CC分支还是uclibc

openwrt 挂载摄像头 mjpg-streamer 相关

AMCap

kmod-i2c-core、
kmod-usb-video、
kmod-video-gspca-core、
kmod-video-gspca-zc3xx;
kmod-video-pwc

build_dir/target-mips_r2_uClibc-0.9.33.2/mjpg-streamer-r148/ipkg-ar71xx/mjpg-streamer/etc/config/mjpg-streamer

====================================
config mjpg-streamer core
option enabled “1”
option device “/dev/video0”
option resolution “640×480”
option fps “30”
option www “/www/webcam”
option port “8080”

======================================
加密码
vi /etc/init.d/mjpg-streamer

service_start /usr/bin/mjpg_streamer –input “input_uvc.so \
–device $device –fps $fps –resolution $resolution” \
–output “output_http.so –www $www –port $port”

改成
service_start /usr/bin/mjpg_streamer –input “input_uvc.so \
–device $device –fps $fps –resolution $resolution” \
–output “output_http.so –www $www -c test:123 –port $port”

用户名为test
密码为123
=======================================
存图,不能有密码

wget http://localhost:8081/?action=snapshot -O /tmp/s.jpg

mjpg_streamer –input “input_uvc.so –device /dev/video0 -r 6
40×480 -f 30” -o “output_file.so -f /tmp/”
=======================================

mjpg_streamer -i “input_uvc.so -r 640×480 -f 30” -o “output_http.so -p 8080 -w /www”
UVC需安装的软件
opkg install kmod-video-core kmod-video-uvc
启动命令
mjpg_streamer -i “input_uvc.so -r 352×288 -y -f 15 -q 80” -o “output_http.so -p 8080 -w /www”
把option enabled “0” 改成1

openwrt 给没有usb的机子加入usb支持

#./target/linux/ar71xx/files/arch/mips/ath79/mach-tl-wr741nd.c

build_dir/linux-ar71xx_generic/linux-3.3.8/arch/mips/ath79/mach-tl-wr741nd.c
开头加入
#include “dev-usb.h”
找到函数
static void __init tl_wr741nd_setup(void)
里边加入
/* USB */
ath79_register_usb();

================================
build_dir/linux-ar71xx_generic/linux-3.3.8/arch/mips/ath79/Kconfig

config ATH79_MACH_TL_WR741ND
bool “TP-LINK TL-WR741ND support”
select SOC_AR724X
select ATH79_DEV_AP9X_PCI if PCI
select ATH79_DEV_ETH
select ATH79_DEV_GPIO_BUTTONS
select ATH79_DEV_LEDS_GPIO
select ATH79_DEV_M25P80
select ATH79_DEV_USB

加入了这个”select ATH79_DEV_USB”

===================================
Compile it for the first time, with the modules/settings you want.
For mounting USB drives, select kernel kmod modules:
USB support: usb2, ohci, storage
Filesystems: ext4, ntfs, vfat
Native language support: cp437,cp852,iso-8859-1, utf8.

If you want R/W NTFS support, select:
Utilities/filesystems/ntfs-3g

Then go to build_dir/linux-ar71xx_generic/linux-3.3.8/arch/mips/ath79
Edit this files:

mach-tl-wr741nd-v4.c
add #include “dev-usb.h” at the top of the file
add ath79_register_usb(); before ath79_register_m25p80(&tl_wr741ndv4_flash_data)

Kconfig
add select ATH79_DEV_USB under “config ATH79_MACH_TL_WR741ND_V4”

Now, run make again. Now the USB will work.

编译openwrt 12.09 r36088 遇到的问题

1. 报错configure: error: no acceptable Java compiler found in $PATH

系统里没有java的编译器。yum install sdk*

2. make[7]: Entering directory `/home/ssj/attitude_adjustment/build_dir/host/otp_src_R15B01/lib/inets/src’

这个倒是没报错,不过比报错更坑人。我等了几个小时,发现还是不动。

于是到`/home/ssj/attitude_adjustment/build_dir/host/otp_src_R15B01/lib/inets/src’

make 了一下,发现报错ccache :未找到。你妹呀,浪费了几个小时

find /home/ssj/attitude_adjustment -name ccache

发现ccache交插编译环境中已经编译好了。于是修改了一下/etc/bashrc

最后加入了export PATH=$PATH:/home/ssj/attitude_adjustment/staging_dir/host/bin/

然后再重连一下ssh,可以找到ccache了,再编译,可以了,不会卡住不动了

openwrt 12.09 把 4M的固件改成8M的方法

首先用git把openwrt的attitude_adjustment代码下载回来
git clone git://git.openwrt.org/12.09/openwrt.git
然后编辑文件 openwrt/target/linux/ar71xx/image/Makefile

比如我编译的是740n-v3
搜740n找到如下内存
$(eval $(call SingleProfile,TPLINK,$(fs_64kraw),TLWR740NV3,tl-wr740n-v3,TL-WR741ND,ttyS0,115200,0×07400003,1,4M))
改成
$(eval $(call SingleProfile,TPLINK,$(fs_64kraw),TLWR740NV3,tl-wr740n-v3,TL-WR741ND,ttyS0,115200,0×07400003,1,8M))
然后再编译,就行了
关于如何编译,和如何搭建环境,去openwrt.org里的wiki看吧,写的不错,语言有中文的

setsockopt

int setsockopt(
SOCKET s,
int level,
int optname,
const char* optval,
int optlen
);

s(套接字): 指向一个打开的套接口描述字
level:(级别): 指定选项代码的类型。
SOL_SOCKET: 基本套接口
IPPROTO_IP: IPv4套接口
IPPROTO_IPV6: IPv6套接口
IPPROTO_TCP: TCP套接口
optname(选项名): 选项名称
optval(选项值): 是一个指向变量的指针 类型:整形,套接口结构, 其他结构类型:linger{}, timeval{ }
optlen(选项长度) :optval 的大小

返回值:标志打开或关闭某个特征的二进制选项
[/code:1:59df4ce128]

========================================================================
SOL_SOCKET
————————————————————————
SO_BROADCAST 允许发送广播数据 int
适用於 UDP socket。其意义是允许 UDP socket 「广播」(broadcast)讯息到网路上。

SO_DEBUG 允许调试 int

SO_DONTROUTE 不查找路由 int

SO_ERROR 获得套接字错误 int

SO_KEEPALIVE 保持连接 int
检 测对方主机是否崩溃,避免(服务器)永远阻塞于TCP连接的输入。 设置该选项后,如果2小时内在此套接口的任一方向都没有数据交换,TCP就自动给对方 发一个保持存活探测分节(keepalive probe)。这是一个对方必须响应的TCP分节.它会导致以下三种情况: 对方接收一切正常:以期望的 ACK响应。2小时后,TCP将发出另一个探测分节。 对方已崩溃且已重新启动:以RST响应。套接口的待处理错误被置为ECONNRESET,套接 口本身则被关闭。 对方无任何响应:源自berkeley的TCP发送另外8个探测分节,相隔75秒一个,试图得到 一个响应。在发出第一个探测分节11分钟15秒后若仍无响应就放弃。套接口的待处理错 误被置为ETIMEOUT,套接口本身则被关闭。如ICMP错误是“host unreachable (主机不 可达)”,说明对方主机并没有崩溃,但是不可达,这种情况下待处理错误被置为 EHOSTUNREACH。

SO_DONTLINGER 若为真,则SO_LINGER选项被禁止。
SO_LINGER 延迟关闭连接 struct linger
上面这两个选项影响close行为
选项 间隔 关闭方式 等待关闭与否
SO_DONTLINGER 不关心 优雅 否
SO_LINGER 零 强制 否
SO_LINGER 非零 优雅 是
若 设置了SO_LINGER(亦即linger结构中的l_onoff域设为非零,参见2.4,4.1.7和4.1.21各节),并设置了零超时间隔,则 closesocket()不被阻塞立即执行,不论是否有排队数据未发送或未被确认。这种关闭方式称为“强制”或“失效”关闭,因为套接口的虚电路立即被 复位,且丢失了未发送的数据。在远端的recv()调用将以WSAECONNRESET出错。
若设置了SO_LINGER并确定了非零的超时间 隔,则closesocket()调用阻塞进程,直到所剩数据发送完毕或超时。这种关闭称为“优雅的”关闭。请注意如果套接口置为非阻塞且 SO_LINGER设为非零超时,则closesocket()调用将以WSAEWOULDBLOCK错误返回。
若在一个流类套接口上设置了 SO_DONTLINGER(也就是说将linger结构的l_onoff域设为零;参见2.4,4.1.7,4.1.21节),则 closesocket()调用立即返回。但是,如果可能,排队的数据将在套接口关闭前发送。请注意,在这种情况下WINDOWS套接口实现将在一段不确 定的时间内保留套接口以及其他资源,这对于想用所以套接口的应用程序来说有一定影响。

SO_OOBINLINE 带外数据放入正常数据流,在普通数据流中接收带外数据 int

SO_RCVBUF 接收缓冲区大小 int
设置接收缓冲区的保留大小
与 SO_MAX_MSG_SIZE 或TCP滑动窗口无关,如果一般发送的包很大很频繁,那么使用这个选项

SO_SNDBUF 发送缓冲区大小 int
设置发送缓冲区的保留大小
与 SO_MAX_MSG_SIZE 或TCP滑动窗口无关,如果一般发送的包很大很频繁,那么使用这个选项
每 个套接口都有一个发送缓冲区和一个接收缓冲区。 接收缓冲区被TCP和UDP用来将接收到的数据一直保存到由应用进程来读。 TCP:TCP通告另一端的窗口大小。 TCP套接口接收缓冲区不可能溢出,因为对方不允许发出超过所通告窗口大小的数据。 这就是TCP的流量控制,如果对方无视窗口大小而发出了超过宙口大小的数据,则接 收方TCP将丢弃它。 UDP:当接收到的数据报装不进套接口接收缓冲区时,此数据报就被丢弃。UDP是没有 流量控制的;快的发送者可以很容易地就淹没慢的接收者,导致接收方的UDP丢弃数据报。

SO_RCVLOWAT 接收缓冲区下限 int
SO_SNDLOWAT 发送缓冲区下限 int
每 个套接口都有一个接收低潮限度和一个发送低潮限度。它们是函数selectt使用的, 接收低潮限度是让select返回“可读”而在套接口接收缓冲区中必须有的数据总量。 ——对于一个TCP或UDP套接口,此值缺省为1。发送低潮限度是让select返回“可写” 而在套接口发送缓冲区中必须有的可用空间。对于TCP套接口,此值常缺省为2048。 对于UDP使用低潮限度, 由于其发送缓冲区中可用空间的字节数是从不变化的,只要 UDP套接口发送缓冲区大小大于套接口的低潮限度,这样的UDP套接口就总是可写的。 UDP没有发送缓冲区,只有发送缓冲区的大小。

SO_RCVTIMEO 接收超时 struct timeval
SO_SNDTIMEO 发送超时 struct timeval
SO_REUSERADDR 允许重用本地地址和端口 int
充许绑定已被使用的地址(或端口号),可以参考bind的man

SO_EXCLUSIVEADDRUSE
独占模式使用端口,就是不充许和其它程序使用SO_REUSEADDR共享的使用某一端口。
在确定多重绑定使用谁的时候,根据一条原则是谁的指定最明确则将包递交给谁,而且没有权限之分,也就是说低级权限的用户是可以重绑定在高级权限如服务启动的端口上的,这是非常重大的一个安全隐患,
如果不想让自己程序被监听,那么使用这个选项

SO_TYPE 获得套接字类型 int
SO_BSDCOMPAT 与BSD系统兼容 int

==========================================================================
IPPROTO_IP
————————————————————————–
IP_HDRINCL 在数据包中包含IP首部 int
这个选项常用于黑客技术中,隐藏自己的IP地址

IP_OPTINOS IP首部选项 int
IP_TOS 服务类型
IP_TTL 生存时间 int

以下IPV4选项用于组播
IPv4 选项 数据类型 描 述
IP_ADD_MEMBERSHIP struct ip_mreq 加入到组播组中
IP_ROP_MEMBERSHIP struct ip_mreq 从组播组中退出
IP_MULTICAST_IF struct ip_mreq 指定提交组播报文的接口
IP_MULTICAST_TTL u_char 指定提交组播报文的TTL
IP_MULTICAST_LOOP u_char 使组播报文环路有效或无效
在头文件中定义了ip_mreq结构:
[code:1:63724de67f]
struct ip_mreq {
struct in_addr imr_multiaddr; /* IP multicast address of group */
struct in_addr imr_interface; /* local IP address of interface */
};
[/code:1:63724de67f]
若进程要加入到一个组播组中,用soket的setsockopt()函数发送该选项。该选项类型是ip_mreq结构,它的第一个字段imr_multiaddr指定了组播组的地址,第二个字段imr_interface指定了接口的IPv4地址。
IP_DROP_MEMBERSHIP
该选项用来从某个组播组中退出。数据结构ip_mreq的使用方法与上面相同。
IP_MULTICAST_IF
该选项可以修改网络接口,在结构ip_mreq中定义新的接口。
IP_MULTICAST_TTL
设置组播报文的数据包的TTL(生存时间)。默认值是1,表示数据包只能在本地的子网中传送。
IP_MULTICAST_LOOP
组播组中的成员自己也会收到它向本组发送的报文。这个选项用于选择是否激活这种状态。

无双 回复于:2003-05-08 21:21:52

IPPRO_TCP
————————————————————————–
TCP_MAXSEG TCP最大数据段的大小 int
获 取或设置TCP连接的最大分节大小(MSS)。返回值是我们的TCP发送给另一端的最大 数据量,它常常就是由另一端用SYN分节通告的MSS,除非我们的TCP选择使用一个比 对方通告的MSS小些的值。如果此值在套接口连接之前取得,则返回值为未从另·—端 收到Mss选项的情况下所用的缺省值。小于此返回值的信可能真正用在连接上,因为譬 如说使用时间戳选项的话,它在每个分节上占用12字节的TCP选项容量。我们的TcP将 发送的每个分节的最大数据量也可在连接存活期内改变,但前提是TCP要支持路径MTU 发现功能。如果到对方的路径改变了,此值可上下调整。
TCP_NODELAY 不使用Nagle算法 int

指定TCP开始发送保持存活探测分节前以秒为单位的连接空闲时间。缺省值至少必须为7200秒,即2小时。此选项仅在SO_KEPALIVEE套接口选项打开时才有效。

TCP_NODELAY 和 TCP_CORK,
这 两个选项都对网络连接的行为具有重要的作用。许多UNIX系统都实现了TCP_NODELAY选项,但是,TCP_CORK则是Linux系统所独有的而 且相对较新;它首先在内核版本2.4上得以实现。此外,其他UNIX系统版本也有功能类似的选项,值得注意的是,在某种由BSD派生的系统上的 TCP_NOPUSH选项其实就是TCP_CORK的一部分具体实现。
TCP_NODELAY和TCP_CORK基本上控制了包的 “Nagle化”,Nagle化在这里的含义是采用Nagle算法把较小的包组装为更大的帧。John Nagle是Nagle算法的发明人,后者就是用他的名字来命名的,他在1984年首次用这种方法来尝试解决福特汽车公司的网络拥塞问题(欲了解详情请参 看IETF RFC 896)。他解决的问题就是所谓的silly window syndrome ,中文称“愚蠢窗口症候群”,具体含义是,因为普遍终端应用程序每产生一次击键操作就会发送一个包,而典型情况下一个包会拥有一个字节的数据载荷以及40 个字节长的包头,于是产生4000%的过载,很轻易地就能令网络发生拥塞,。 Nagle化后来成了一种标准并且立即在因特网上得以实现。它现在已经成为缺省配置了,但在我们看来,有些场合下把这一选项关掉也是合乎需要的。
现 在让我们假设某个应用程序发出了一个请求,希望发送小块数据。我们可以选择立即发送数据或者等待产生更多的数据然后再一次发送两种策略。如果我们马上发送 数据,那么交互性的以及客户/服务器型的应用程序将极大地受益。例如,当我们正在发送一个较短的请求并且等候较大的响应时,相关过载与传输的数据总量相比 就会比较低,而且,如果请求立即发出那么响应时间也会快一些。以上操作可以通过设置套接字的TCP_NODELAY选项来完成,这样就禁用了Nagle算 法。
另外一种情况则需要我们等到数据量达到最大时才通过网络一次发送全部数据,这种数据传输方式有益于大量数据的通信性能,典型的应用就是文件服 务器。应用 Nagle算法在这种情况下就会产生问题。但是,如果你正在发送大量数据,你可以设置TCP_CORK选项禁用Nagle化,其方式正好同 TCP_NODELAY相反(TCP_CORK 和 TCP_NODELAY 是互相排斥的)。下面就让我们仔细分析下其工作原理。
假设应用程序 使用sendfile()函数来转移大量数据。应用协议通常要求发送某些信息来预先解释数据,这些信息其实就是报头内容。典型情况下报头很小,而且套接字 上设置了TCP_NODELAY。有报头的包将被立即传输,在某些情况下(取决于内部的包计数器),因为这个包成功地被对方收到后需要请求对方确认。这 样,大量数据的传输就会被推迟而且产生了不必要的网络流量交换。
但是,如果我们在套接字上设置了TCP_CORK(可以比喻为在管道上插入 “塞子”)选项,具有报头的包就会填补大量的数据,所有的数据都根据大小自动地通过包传输出去。当数据传输完成时,最好取消TCP_CORK 选项设置给连接“拔去塞子”以便任一部分的帧都能发送出去。这同“塞住”网络连接同等重要。
总而言之,如果你肯定能一起发送多个数据集合(例如HTTP响应的头和正文),那么我们建议你设置TCP_CORK选项,这样在这些数据之间不存在延迟。能极大地有益于WWW、FTP以及文件服务器的性能,同时也简化了你的工作。示例代码如下:

intfd, on = 1;

/* 此处是创建套接字等操作,出于篇幅的考虑省略*/

setsockopt (fd, SOL_TCP, TCP_CORK, &on, sizeof (on)); /* cork */
write (fd, …);
fprintf (fd, …);
sendfile (fd, …);
write (fd, …);
sendfile (fd, …);

on = 0;
setsockopt (fd, SOL_TCP, TCP_CORK, &on, sizeof (on)); /* 拔去塞子 */

不幸的是,许多常用的程序并没有考虑到以上问题。例如,Eric Allman编写的sendmail就没有对其套接字设置任何选项。

Apache HTTPD 是因特网上最流行的Web服务器,它的所有套接字就都设置了TCP_NODELAY选项,而且其性能也深受大多数用户的满意。这是为什么呢?答案就在于实 现的差别之上。由BSD衍生的TCP/IP协议栈(值得注意的是FreeBSD)在这种状况下的操作就不同。当在TCP_NODELAY 模式下提交大量小数据块传输时,大量信息将按照一次write()函数调用发送一块数据的方式发送出去。然而,因为负责请求交付确认的记数器是面向字节而 非面向包(在 Linux上)的,所以引入延迟的概率就降低了很多。结果仅仅和全部数据的大小有关系。而 Linux 在第一包到达之后就要求确认,FreeBSD则在进行如此操作之前会等待好几百个包。

在Linux系统上,TCP_NODELAY的效果同习惯于BSD TCP/IP协议栈的开发者所期望的效果有很大不同,而且在Linux上的Apache性能表现也会更差些。其他在Linux上频繁采用TCP_NODELAY的应用程序也有同样的问题。

TCP_DEFER_ACCEPT

我 们首先考虑的第1个选项是TCP_DEFER_ACCEPT(这是Linux系统上的叫法,其他一些操作系统上也有同样的选项但使用不同的名字)。为了理 解TCP_DEFER_ACCEPT选项的具体思想,我们有必要大致阐述一下典型的HTTP客户/服务器交互过程。请回想下TCP是如何与传输数据的目标 建立连接的。在网络上,在分离的单元之间传输的信息称为IP包(或IP 数据报)。一个包总有一个携带服务信息的包头,包头用于内部协议的处理,并且它也可以携带数据负载。服务信息的典型例子就是一套所谓的标志,它把包标记代 表TCP/IP协议栈内的特殊含义,例如收到包的成功确认等等。通常,在经过“标记”的包里携带负载是完全可能的,但有时,内部逻辑迫使TCP/IP协议 栈发出只有包头的IP包。这些包经常会引发讨厌的网络延迟而且还增加了系统的负载,结果导致网络性能在整体上降低。
现在服务器创建了一个套接字同 时等待连接。TCP/IP式的连接过程就是所谓“3次握手”。首先,客户程序发送一个设置SYN标志而且不带数据负载的TCP包(一个SYN包)。服务器 则以发出带SYN/ACK标志的数据包(一个SYN/ACK包)作为刚才收到包的确认响应。客户随后发送一个ACK包确认收到了第2个包从而结束连接过 程。在收到客户发来的这个SYN/ACK包之后,服务器会唤醒一个接收进程等待数据到达。当3次握手完成后,客户程序即开始把“有用的”的数据发送给服务 器。通常,一个HTTP请求的量是很小的而且完全可以装到一个包里。但是,在以上的情况下,至少有4个包将用来进行双向传输,这样就增加了可观的延迟时 间。此外,你还得注意到,在“有用的”数据被发送之前,接收方已经开始在等待信息了。
为了减轻这些问题所带来的影响,Linux(以及其他的一些 操作系统)在其TCP实现中包括了TCP_DEFER_ACCEPT选项。它们设置在侦听套接字的服务器方,该选项命令内核不等待最后的ACK包而且在第 1个真正有数据的包到达才初始化侦听进程。在发送SYN/ACK包之后,服务器就会等待客户程序发送含数据的IP包。现在,只需要在网络上传送3个包了, 而且还显著降低了连接建立的延迟,对HTTP通信而言尤其如此。
这一选项在好些操作系统上都有相应的对等物。例如,在FreeBSD上,同样的行为可以用以下代码实现:

/* 为明晰起见,此处略去无关代码 */
struct accept_filter_arg af = { “dataready”, “” };
setsockopt(s, SOL_SOCKET, SO_ACCEPTFILTER, &af, sizeof(af));
这 个特征在FreeBSD上叫做“接受过滤器”,而且具有多种用法。不过,在几乎所有的情况下其效果与TCP_DEFER_ACCEPT是一样的:服务器不 等待最后的ACK包而仅仅等待携带数据负载的包。要了解该选项及其对高性能Web服务器的重要意义的更多信息请参考Apache文档上的有关内容。
就HTTP 客户/服务器交互而言,有可能需要改变客户程序的行为。客户程序为什么要发送这种“无用的”ACK包呢?这是因为,TCP协议栈无法知道ACK包的状态。 如果采用FTP而非HTTP,那么客户程序直到接收了FTP服务器提示的数据包之后才发送数据。在这种情况下,延迟的ACK将导致客户/服务器交互出现延 迟。为了确定ACK是否必要,客户程序必须知道应用程序协议及其当前状态。这样,修改客户行为就成为必要了。
对Linux客户程序来说,我们还可 以采用另一个选项,它也被叫做TCP_DEFER_ACCEPT。我们知道,套接字分成两种类型,侦听套接字和连接套接字,所以它们也各自具有相应的 TCP选项集合。因此,经常同时采用的这两类选项却具有同样的名字也是完全可能的。在连接套接字上设置该选项以后,客户在收到一个SYN/ACK包之后就 不再发送ACK包,而是等待用户程序的下一个发送数据请求;因此,服务器发送的包也就相应减少了。

TCP_QUICKACK

阻 止因发送无用包而引发延迟的另一个方法是使用TCP_QUICKACK选项。这一选项与 TCP_DEFER_ACCEPT不同,它不但能用作管理连接建立过程而且在正常数据传输过程期间也可以使用。另外,它能在客户/服务器连接的任何一方设 置。如果知道数据不久即将发送,那么推迟ACK包的发送就会派上用场,而且最好在那个携带数据的数据包上设置ACK 标志以便把网络负载减到最小。当发送方肯定数据将被立即发送(多个包)时,TCP_QUICKACK 选项可以设置为0。对处于“连接”状态下的套接字该选项的缺省值是1,首次使用以后内核将把该选项立即复位为1(这是个一次性的选项)。
在某些情形下,发出ACK包则非常有用。ACK包将确认数据块的接收,而且,当下一块被处理时不至于引入延迟。这种数据传输模式对交互过程是相当典型的,因为此类情况下用户的输入时刻无法预测。在Linux系统上这就是缺省的套接字行为。
在 上述情况下,客户程序在向服务器发送HTTP请求,而预先就知道请求包很短所以在连接建立之后就应该立即发送,这可谓HTTP的典型工作方式。既然没有必 要发送一个纯粹的ACK包,所以设置TCP_QUICKACK为0以提高性能是完全可能的。在服务器方,这两种选项都只能在侦听套接字上设置一次。所有的 套接字,也就是被接受呼叫间接创建的套接字则会继承原有套接字的所有选项。
通过TCP_CORK、TCP_DEFER_ACCEPT和 TCP_QUICKACK选项的组合,参与每一HTTP交互的数据包数量将被降低到最小的可接受水平(根据TCP协议的要求和安全方面的考虑)。结果不仅 是获得更快的数据传输和请求处理速度而且还使客户/服务器双向延迟实现了最小化。

二、使用例子说明

1.closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket:
BOOL bReuseaddr=TRUE;
setsockopt(s,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(BOOL));
2. 如果要已经处于连接状态的soket在调用closesocket后强制关闭,不经历
TIME_WAIT的过程:
BOOL bDontLinger = FALSE;
setsockopt(s,SOL_SOCKET,SO_DONTLINGER,(const char*)&bDontLinger,sizeof(BOOL));
3.在send(),recv()过程中有时由于网络状况等原因,发收不能预期进行,而设置收发时限:
int nNetTimeout=1000;//1秒
//发送时限
setsockopt(socket,SOL_S0CKET,SO_SNDTIMEO,(char *)&nNetTimeout,sizeof(int));
//接收时限
setsockopt(socket,SOL_S0CKET,SO_RCVTIMEO,(char *)&nNetTimeout,sizeof(int));
4.在send()的时候,返回的是实际发送出去的字节(同步)或发送到socket缓冲区的字节
(异步);系统默认的状态发送和接收一次为8688字节(约为8.5K);在实际的过程中发送数据
和接收数据量比较大,可以设置socket缓冲区,而避免了send(),recv()不断的循环收发:
// 接收缓冲区
int nRecvBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));
//发送缓冲区
int nSendBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));
5. 如果在发送数据的时,希望不经历由系统缓冲区到socket缓冲区的拷贝而影响
程序的性能:
int nZero=0;
setsockopt(socket,SOL_S0CKET,SO_SNDBUF,(char *)&nZero,sizeof(nZero));
6.同上在recv()完成上述功能(默认情况是将socket缓冲区的内容拷贝到系统缓冲区):
int nZero=0;
setsockopt(socket,SOL_S0CKET,SO_RCVBUF,(char *)&nZero,sizeof(int));
7.一般在发送UDP数据报的时候,希望该socket发送的数据具有广播特性:
BOOL bBroadcast=TRUE;
setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char*)&bBroadcast,sizeof(BOOL));
8.在client连接服务器过程中,如果处于非阻塞模式下的socket在connect()的过程中可
以设置connect()延时,直到accpet()被呼叫(本函数设置只有在非阻塞的过程中有显著的
作用,在阻塞的函数调用中作用不大)
BOOL bConditionalAccept=TRUE;
setsockopt(s,SOL_SOCKET,SO_CONDITIONAL_ACCEPT,(const char*)&bConditionalAccept,sizeof(BOOL));
9.如果在发送数据的过程中(send()没有完成,还有数据没发送)而调用了closesocket(),以前我们
一般采取的措施是”从容关闭”shutdown(s,SD_BOTH),但是数据是肯定丢失了,如何设置让程序满足具体
应用的要求(即让没发完的数据发送出去后在关闭socket)?
struct linger {
u_short l_onoff;
u_short l_linger;
};
linger m_sLinger;
m_sLinger.l_onoff=1;//(在closesocket()调用,但是还有数据没发送完毕的时候容许逗留)
// 如果m_sLinger.l_onoff=0;则功能和2.)作用相同;
m_sLinger.l_linger=5;//(容许逗留的时间为5秒)
setsockopt(s,SOL_SOCKET,SO_LINGER,(const char*)&m_sLinger,sizeof(linger));
setsockopt()用法
2007/12/05 19:01
一下来源于互联网:

1.closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket:
BOOL bReuseaddr=TRUE;
setsockopt(s,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(BOOL));

2. 如果要已经处于连接状态的soket在调用closesocket后强制关闭,不经历
TIME_WAIT的过程:
BOOL bDontLinger = FALSE;
setsockopt(s,SOL_SOCKET,SO_DONTLINGER,(const char*)&bDontLinger,sizeof(BOOL));

3.在send(),recv()过程中有时由于网络状况等原因,发收不能预期进行,而设置收发时限:
int nNetTimeout=1000;//1秒
//发送时限
setsockopt(socket,SOL_S0CKET,SO_SNDTIMEO,(char *)&nNetTimeout,sizeof(int));
//接收时限
setsockopt(socket,SOL_S0CKET,SO_RCVTIMEO,(char *)&nNetTimeout,sizeof(int));

4.在send()的时候,返回的是实际发送出去的字节(同步)或发送到socket缓冲区的字节
(异步);系统默认的状态发送和接收一次为8688字节(约为8.5K);在实际的过程中发送数据
和接收数据量比较大,可以设置socket缓冲区,而避免了send(),recv()不断的循环收发:
// 接收缓冲区
int nRecvBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));
//发送缓冲区
int nSendBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));
5. 如果在发送数据的时,希望不经历由系统缓冲区到socket缓冲区的拷贝而影响
程序的性能:
int nZero=0;
setsockopt(socket,SOL_S0CKET,SO_SNDBUF,(char *)&nZero,sizeof(nZero));
6.同上在recv()完成上述功能(默认情况是将socket缓冲区的内容拷贝到系统缓冲区):
int nZero=0;
setsockopt(socket,SOL_S0CKET,SO_RCVBUF,(char *)&nZero,sizeof(int));
7.一般在发送UDP数据报的时候,希望该socket发送的数据具有广播特性:
BOOL bBroadcast=TRUE;
setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char*)&bBroadcast,sizeof(BOOL));
8.在client连接服务器过程中,如果处于非阻塞模式下的socket在connect()的过程中可
以设置connect()延时,直到accpet()被呼叫(本函数设置只有在非阻塞的过程中有显著的
作用,在阻塞的函数调用中作用不大)
BOOL bConditionalAccept=TRUE;
setsockopt(s,SOL_SOCKET,SO_CONDITIONAL_ACCEPT,(const char*)&bConditionalAccept,sizeof(BOOL));
9.如果在发送数据的过程中(send()没有完成,还有数据没发送)而调用了closesocket(),以前我们
一般采取的措施是”从容关闭”shutdown(s,SD_BOTH),但是数据是肯定丢失了,如何设置让程序满足具体
应用的要求(即让没发完的数据发送出去后在关闭socket)?
struct linger {
u_short l_onoff;
u_short l_linger;
};
linger m_sLinger;
m_sLinger.l_onoff=1;//(在closesocket()调用,但是还有数据没发送完毕的时候容许逗留)
// 如果m_sLinger.l_onoff=0;则功能和2.)作用相同;
m_sLinger.l_linger=5;//(容许逗留的时间为5秒)
setsockopt(s,SOL_SOCKET,SO_LINGER,(const char*)&m_sLinger,sizeof(linger));