Linux下串口编程入门

1. 串口简介

串行口是计算机一种常用的接口,具有连接线少,通讯简单,得到广泛的使用.常用的串口是 RS-232-C 接口(又称 EIA RS-232-C)它是在 1970 年由美国电子工业协会(EIA)联合贝尔系统、 调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准.它的全名是"数据终端设备(DTE)和数据通讯设备(DCE)之间串行二进制数据交换接口技术标准"该标准规定采用一个 25 个脚的 DB25 连接器,对连接器的每个引脚的信号内容加以规定,还对各种信号的电平加以规定.传输距离在码元畸变小于 4% 的情况下,传输电缆长度应为 50 英尺.

Linux 操作系统从一开始就对串行口提供了很好的支持,本文就 Linux 下的串行口通讯编程进行简单的介绍,如果要非常深入了解,建议看看本文所参考的 《Serial Programming Guide for POSIX Operating Systems》

计算机串口的引脚说明

序号信号名称符号流向功能
2发送数据TXDDTE→DCEDTE发送串行数据
3接收数据RXDDTE←DCEDTE 接收串行数据
4请求发送RTSDTE→DCEDTE 请求 DCE 将线路切换到发送方式
5允许发送CTSDTE←DCEDCE 告诉 DTE 线路已接通可以发送数据
6数据设备准备好DSRDTE←DCEDCE 准备好
7信号地  信号公共地
8载波检测DCDDTE←DCE表示 DCE 接收到远程载波
20数据终端准备好DTRDTE→DCEDTE 准备好
22振铃指示RIDTE←DCE表示 DCE 与线路接通,出现振铃

2. 串口操作

串口操作需要的头文件

复制代码

1 #include     <stdio.h>      /*标准输入输出定义*/
2 #include     <stdlib.h>     /*标准函数库定义*/
3 #include     <unistd.h>     /*Unix 标准函数定义*/
4 #include     <sys/types.h>  
5 #include     <sys/stat.h>   
6 #include     <fcntl.h>      /*文件控制定义*/
7 #include     <termios.h>    /*PPSIX 终端控制定义*/
8 #include     <errno.h>      /*错误号定义*/

复制代码

3. 打开串口

Linux系统上一般有一个或者多个串口,而这些串口设备文件名字比较奇怪,如比下面这样

操作系统串口1串口2USB/RS-232转换器
WindowsCOM1COM2-
Linux/dev/ttyS0/dev/ttyS1/dev/ttyUSB0

因为串口和其他设备一样,在类Unix系统中都是以设备文件的形式存在的,所以,理所当然得你可以使用open(2)系统调用/函数来访问它.但Linux系统中却有一个稍微不方便的地方,那就是普通用户一般不能直接访问设备文件.你可以选择以下方式做一些调整,以便你编写的程序可以访问串口.

  • 改变设备文件的访问权限设置 [#cd9bd1e0]
  • 以root超级用户的身份运行程序 [#kdd0e577]
  • 将你的程序编写位setuid程序,以串口设备所有者的身份运行程序 [#s7b703ff]

OK.假如你已经准备好了让串口设备文件可以被所有用户访问,你可以在Linux系统中实验一下下面这个程序,它可以打开计算机的串口1.

复制代码

1 int fd;
2 /*以读写方式打开串口*/
3 fd = open( "/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
4 if (-1 == fd){ 
5 /* 不能打开串口一*/ 
6 perror(" 提示错误!"); 
7 }

复制代码

打开串口连接的时候,程序在open函数中除了Read+Write模式以外还指定了两个选项;

标志O_NOCTTY可以告诉UNIX这个程序不会成为这个端口上的“控制终端”.如果不这样做的话,所有的输入,比如键盘上过来的Ctrl+C中止信号等等,会影响到你的进程.而有些程序比如getty(1M/8)则会在打开登录进程的时候使用这个特性,但是通常情况下,用户程序不会使用这个行为.

O_NDELAY标志则是告诉UNIX,这个程序并不关心DCD信号线的状态——也就是不关心端口另一端是否已经连接.如果不指定这个标志的话,除非DCD信号线上有space电压否则这个程序会一直睡眠.

4. 设置串口

最基本的设置串口包括波特率设置,效验位和停止位设置.

很多系统都支持POSIX终端(串口)接口.程序可以利用这个接口来改变终端的参数,比如,波特率,字符大小等等.要使用这个端口的话,你必须将<termios.h>头文件包含到你的程序中.这个头文件中定义了终端控制结构体和POSIX控制函数.

与串口操作相关的最重要的两个POSIX函数可能就是tcgetattr(3)和tcsetattr(3).顾名思义,这两个函数分别用来取得设设置终端的属性.调用这两个函数的时候,你需要提供一个包含着所有串口选项的termios结构体,串口的设置主要是设置struct termios结构体的各成员值.

成员描述
c_cflag控制选项
c_lflag行选项
c_iflag输入选项
c_oflag输出选项
c_cc控制字符
c_ispeed输入波特率(NEW)
c_ospeed输出波特率(NEW)

通过termio结构体的c_cflag成员可以控制波特率,数据的比特数,parity,停止位和硬件流控制,下面这张表列出了所有可以使用的常数

常量描述
CBAUDBit mask for baud rate
B00 baud (drop DTR)
B5050 baud
B7575 baud
B110110 baud
B134134.5 baud
B150150 baud
B200200 baud
B300300 baud
B600600 baud
B12001200 baud
B18001800 baud
B24002400 baud
B48004800 baud
B96009600 baud
B1920019200 baud
B3840038400 baud
B5760057,600 baud
B7680076,800 baud
B115200115,200 baud
EXTAExternal rate clock
EXTBExternal rate clock
CSIZEBit mask for data bits
CS55 data bits
CS66 data bits
CS77 data bits
CS88 data bits
CSTOPB2 stop bits (1 otherwise)
CREADEnable receiver
PARENBEnable parity bit
PARODDUse odd parity instead of even
HUPCLHangup (drop DTR) on last close
CLOCALLocal line - do not change "owner" of port
LOBLKBlock job control output
CNEW_RTSCTS/CRTSCTSEnable hardware flow control (not supported on all platforms)

在传统的POSIX编程中,当连接一个本地的(不通过调制解调器)或者远程的终端(通过调制解调器)时,这里有两个选项应当一直打开,一个是CLOCAL,另一个是CREAD.这两个选项可以保证你的程序不会变成端口的所有者,而端口所有者必须去处理发散性作业控制和挂断信号,同时还保证了串行接口驱动会读取过来的数据字节.

波特率常数(CBAUD,B9600等等)通常指用到那些不支持c_ispeed和c_ospeed成员的旧的接口上.后面文章将会提到如何使用其他POSIX函数来设置波特率.

千万不要直接用使用数字来初始化c_cflag(当然还有其他标志),最好的方法是使用位运算的与或非组合来设置或者清除这个标志.不同的操作系统版本会使用不同的位模式,使用常数定义和位运算组合来避免重复工作从而提高程序的可移植性.

波特率设置

不同的操作系统会将波特率存储在不同的位置.旧的编程接口将波特率存储在上表所示的c_cflag成员中,而新的接口实装则提供了c_ispeed和c_ospeed成员来保存实际波特率的值.

程序中可是使用cfsetospeed(3)和cfsetispeed(3)函数在termios结构体中设置波特率而不用去管底层操作系统接口.下面的代码是个非常典型的设置波特率的例子.

复制代码

 1 struct termios options;
 2 
 3 /*
 4  * Get the current options for the port...
 5  */
 6 tcgetattr(fd, &options);
 7 /*
 8  * Set the baud rates to 19200...
 9  */
10 cfsetispeed(&options, B19200);
11 cfsetospeed(&options, B19200);
12 
13 /*
14  * Enable the receiver and set local mode...
15  */
16 options.c_cflag |= (CLOCAL | CREAD);
17 
18 /*
19  * Set the new options for the port...
20  */
21 tcsetattr(fd, TCSANOW, &options);

复制代码

函数tcgetattr(3)会将当前串口配置回填到termio结构体option中.然后,程序设置了输入输出的波特率并且将本地模式(CLOCAL)和串行数据接收(CREAD)设置为有效,接着将新的配置作为参数传递给函数tcsetattr(3).常量TCSANOW标志所有改变必须立刻生效而不用等到数据传输结束.其他另一些常数可以保证等待数据结束或者刷新输入输出之后再生效.

常量描述
TCSANOWMake changes now without waiting for data to complete
TCSADRAINWait until everything has been transmitted
TCSAFLUSHFlush input and output buffers and make the change

 

 

 

 

不同的系统上可能支持不同的输入输出速度,所以,通过串口连接两台机器或者设备的时候,应该将波特率设置成两者中较小的那个,即MIN(speed1, speed2).

设置字符大小

设置字符大小的时候,这里却没有像设置波特率那么方便的函数.所以,程序中需要一些位掩码运算来把事情搞定.字符大小以比特为单位指定:

1 options.c_flag &= ~CSIZE; /* Mask the character size bits */
2 options.c_flag |= CS8;    /* Select 8 data bits */

设置奇偶校验和停止位

与设置字符大小的方式差不多,这里仍然需要组合一些位掩码来将奇偶校验设为有效和奇偶校验的类型.UNIX串口驱动可以生成even,odd和no parity位码.设置space奇偶校验需要耍点小手段.

  • No parity (8N1)
1 options.c_cflag &= ~PARENB
2 options.c_cflag &= ~CSTOPB
3 options.c_cflag &= ~CSIZE;
4 options.c_cflag |= CS8;
  • Even parity (7E1)
1 options.c_cflag |= PARENB
2 options.c_cflag &= ~PARODD
3 options.c_cflag &= ~CSTOPB
4 options.c_cflag &= ~CSIZE;
5 options.c_cflag |= CS7;
  • Odd parity (7O1)
1 options.c_cflag |= PARENB
2 options.c_cflag |= PARODD
3 options.c_cflag &= ~CSTOPB
4 options.c_cflag &= ~CSIZE;
5 options.c_cflag |= CS7;
  • Space parity is setup the same as no parity (7S1)
1 options.c_cflag &= ~PARENB
2 options.c_cflag &= ~CSTOPB
3 options.c_cflag &= ~CSIZE;
4 options.c_cflag |= CS8;

设置效验的函数实例:

复制代码

 1 /**
 2 *@brief   设置串口数据位,停止位和效验位
 3 *@param  fd     类型  int  打开的串口文件句柄
 4 *@param  databits 类型  int 数据位   取值 为 7 或者8
 5 *@param  stopbits 类型  int 停止位   取值为 1 或者2
 6 *@param  parity  类型  int  效验类型 取值为N,E,O,,S
 7 */
 8 int set_Parity(int fd,int databits,int stopbits,int parity)
 9 { 
10     struct termios options; 
11     if  ( tcgetattr( fd,&options)  !=  0) { 
12         perror("SetupSerial 1");     
13         return(FALSE);  
14     }
15     options.c_cflag &= ~CSIZE; 
16     switch (databits) /*设置数据位数*/
17     {   
18     case 7:        
19         options.c_cflag |= CS7; 
20         break;
21     case 8:     
22         options.c_cflag |= CS8;
23         break;   
24     default:    
25         fprintf(stderr,"Unsupported data size\n"); return (FALSE);  
26     }
27 switch (parity) 
28 {   
29     case 'n':
30     case 'N':    
31         options.c_cflag &= ~PARENB;   /* Clear parity enable */
32         options.c_iflag &= ~INPCK;     /* Enable parity checking */ 
33         break;  
34     case 'o':   
35     case 'O':     
36         options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/  
37         options.c_iflag |= INPCK;             /* Disnable parity checking */ 
38         break;  
39     case 'e':  
40     case 'E':   
41         options.c_cflag |= PARENB;     /* Enable parity */    
42         options.c_cflag &= ~PARODD;   /* 转换为偶效验*/     
43         options.c_iflag |= INPCK;       /* Disnable parity checking */
44         break;
45     case 'S': 
46     case 's':  /*as no parity*/   
47         options.c_cflag &= ~PARENB;
48         options.c_cflag &= ~CSTOPB;break;  
49     default:   
50         fprintf(stderr,"Unsupported parity\n");    
51         return (FALSE);  
52     }  
53 /* 设置停止位*/  
54 switch (stopbits)
55 {   
56     case 1:    
57         options.c_cflag &= ~CSTOPB;  
58         break;  
59     case 2:    
60         options.c_cflag |= CSTOPB;  
61        break;
62     default:    
63          fprintf(stderr,"Unsupported stop bits\n");  
64          return (FALSE); 
65 } 
66 /* Set input parity option */ 
67 if (parity != 'n')   
68     options.c_iflag |= INPCK; 
69 tcflush(fd,TCIFLUSH);
70 options.c_cc[VTIME] = 150; /* 设置超时15 seconds*/   
71 options.c_cc[VMIN] = 0; /* Update the options and do it NOW */
72 if (tcsetattr(fd,TCSANOW,&options) != 0)   
73 { 
74     perror("SetupSerial 3");   
75     return (FALSE);  
76 } 
77 return (TRUE);  
78 }

复制代码

需要注意的是:

如果不是开发终端之类的,只是串口传输数据,而不需要串口来处理,那么使用原始模式(Raw Mode)方式来通讯,设置方式如下:

1 options.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);  /*Input*/
2 options.c_oflag  &= ~OPOST;   /*Output*/

设置硬件流控制

某些版本的UNIX系统支持通过CTS(Clear To Send)和RTS(Request To Send)信号线来设置硬件流控制.如果系统上定义了CNEW_RTSCTS和CRTSCTS常量,那么很可能它会支持硬件流控制.使用下面的方法将硬件流控制设置成有效:

1 options.c_cflag |= CNEW_RTSCTS;    /* Also called CRTSCTS

将它设置成为无效的方法与此类似:

1 options.c_cflag &= ~CNEW_RTSCTS;

本地设置

本地模式成员变量c_lflag可以控制串口驱动怎样控制输入字符.通常,你可能需要通过c_lflag成员来设置经典输入和原始输入模式。

ISIGEnable SIGINTR, SIGSUSP, SIGDSUSP, and SIGQUIT signals
ICANONEnable canonical input (else raw)
XCASEMap uppercase \lowercase (obsolete)
ECHOEnable echoing of input characters
ECHOEEcho erase character as BS-SP-BS
ECHOKEcho NL after kill character
ECHONLEcho NL
NOFLSHDisable flushing of input buffers after interrupt or quit characters
IEXTENEnable extended functions
ECHOCTLEcho control characters as ^char and delete as ~?
ECHOPRTEcho erased character as character erased
ECHOKEBS-SP-BS entire line on line kill
FLUSHOOutput being flushed
PENDINRetype pending input at next read or input char
TOSTOPSend SIGTTOU for background output

成员变量c_lflag可以使用的常量

选择经典输入

经典输入是以面向行设计的.在经典输入模式中输入字符会被放入一个缓冲之中,这样可以以与用户交互的方式编辑缓冲的内容,直到收到CR(carriage return)或者LF(line feed)字符.

选择使用经典输入模式的时候,你通常需要选择ICANON,ECHO和ECHOE选项:

1 options.c_lflag |= (ICANON | ECHO | ECHOE);

选择原始输入

原始输入根本不会被处理.输入字符只是被原封不动的接收.一般情况中,如果要使用原始输入模式,程序中需要去掉ICANON,ECHO,ECHOE和ISIG选项:

1 options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

输入选项

可以通过输入模式成员c_iflag来控制从端口上收到的字符的输入过程.与c_cflag一样,c_iflag的最终值是想要使用的所有状态的位运算OR的组合.

常量描述
INPCKEnable parity check
IGNPARIgnore parity errors
PARMRKMark parity errors
ISTRIPStrip parity bits
IXONEnable software flow control (outgoing)
IXOFFEnable software flow control (incoming)
IXANYAllow any character to start flow again
IGNBRKIgnore break condition
BRKINTSend a SIGINT when a break condition is detected
INLCRMap NL to CR
IGNCRIgnore CR
ICRNLMap CR to NL
IUCLCMap uppercase to lowercase
IMAXBELEcho BEL on input line too long

c_iflag成员可以使用的常量

设置输入奇偶校验选项

当程序在c_cflag中设置了奇偶校验成员(PARENB)的时候,程序就需要将输入奇偶校验设置成为有效.与奇偶校验相关的常量有INPCK,IGNPAR,PARMRK和ISTRIP.一般情况下,你可能需要选择INPCK和ISTRIP将奇偶校验设置为有效同时从接收字串中脱去奇偶校验位:

1 options.c_iflag |= (INPCK | ISTRIP);

IGNPAR是一个比较危险选项,即便有错误发生时,它也会告诉串口驱动直接忽略奇偶校验错误给数据放行.这个选项在测试链接的通讯质量时比较有用而通常不会被用在实际程序中.

PARMRK会导致奇偶校验错误被标志成特殊字符加入到输入流之中.如果IGNPAR选项也是有效的,那么一个NUL(八进制000)字符会被加入到发生奇偶校验错误的字符前面.否则,DEL(八进制177)和NUL字符会和出错的字符一起送出.

设置软件流控制

软件流控制可以通过IXON,IXOFF和IXANY常量设置成有效:

1 options.c_iflag |= (IXON | IXOFF | IXANY);

将其设置为无效的时候,很简单,只需要对这些位取反:

1 options.c_iflag &= ~(IXON | IXOFF | IXANY);

XON(start data)和XOFF(stop data)字符却是在c_cc数组中定义的,下面会详细描述这个数组.

输出选项

成员变量c_oflag之中包括了输出过滤选项.和输入模式相似,程序可以选择使用经过加工的或者原始的数据输出.

常量描述
OPOSTPostprocess output (not set = raw output)
OLCUCMap lowercase to uppercase
ONLCRMap NL to CR-NL
OCRNLMap CR to NL
NOCRNo CR output at column 0
ONLRETNL performs CR function
OFILLUse fill characters for delay
OFDELFill character is DEL
NLDLYMask for delay time needed between lines
NL0No delay for NLs
NL1Delay further output after newline for 100 milliseconds
CRDLYMask for delay time needed to return carriage to left column
CR0No delay for CRs
CR1Delay after CRs depending on current column position
CR2Delay 100 milliseconds after sending CRs
CR3Delay 150 milliseconds after sending CRs
TABDLYMask for delay time needed after TABs
TAB0No delay for TABs
TAB1Delay after TABs depending on current column position
TAB2Delay 100 milliseconds after sending TABs
TAB3Expand TAB characters to spaces
BSDLYMask for delay time needed after BSs
BS0No delay for BSs
BS1Delay 50 milliseconds after sending BSs
VTDLYMask for delay time needed after VTs
VT0No delay for VTs
VT1Delay 2 seconds after sending VTs
FFDLYMask for delay time needed after FFs
FF0No delay for FFs
FF1Delay 2 seconds after sending FFs

c_oflag成员的常量

选择加工过的输出

通过在c_oflag成员变量中设置OPOST选项的方法程序可以选择加工过的输入.

1 options.c_oflag |= OPOST;

在所有选项当中,你可能只需要使用ONLCR选项来将行分隔符映射到CR-LF组合对上.其他选项主要是历史遗留,仅仅与行打印机和终端跟不上串行数据的年代有关.

选择原始输出

原始输出方式可以通过在c_oflag中重置OPOST选项来选择:

1 options.c_oflag &= ~OPOST;

如果OPOST选项被设置成无效的话,其他c_oflag中的选项都会失效.

控制字符

字符数组c_cc里面包括了控制字符的定义和超时参数.这个数组的每个元素都是以常量定义的.

常量描述
VINTRInterruptCTRL-C
VQUITQuitCTRL-Z
VERASEEraseBackspace (BS)
VKILLKill-lineCTRL-U
VEOFEnd-of-fileCTRL-D
VEOLEnd-of-lineCarriage return (CR)
VEOL2Second end-of-lineLine feed (LF)
VMINMinimum number of characters to read-
VSTARTStart flowCTRL-Q (XON)
VSTOPStop flowCTRL-S (XOFF)
VTIMETime to wait for data (tenths of seconds)-

 

 

 

 

成员变量c_cc中的控制字符

设置软件流控制字符

用来做软件流控制的字符包含在数组c_cc的VSTART和VSTOP元素里面.通常情况下,它们应该被设置成DC1(八进制021)和DC3(八进制023),它们在ASCII标准中代表着XON和XOFF字符.

设置读取超时

UNIX串口驱动提供了设置字符和包超时的能力.数组c_cc中有两个元素可以用来设置超时:VMIN和VTIME.在经典输入模式或者通过open(2)和fcntl(2)函数传递NDELAY选项时,超时设置会被忽略.

VMIN可以指定读取的最小字符数.如果它被设置为0,那么VTIME值则会指定每个字符读取的等待时间.

如果VMIN不为零,VTIME会指定等待第一个字符读取操作的时间.如果在这个指定时间中可以开始读取某个字符,直到VMIN个数的所有字符全部被读取,其他读取操作将会被阻塞(等待).也就是说,一旦读取第一个字符,串口驱动的预期就是接收到整个字符包(一共VMIN字节).如果在允许的时间内没有字符被读取,那么read(2)调用就会返回0.通过这个方法可以确切得告诉串口驱动程序需要读取N个字节,而且read(2)调用只会返回N或者0.然而,超时设置只对第一个字符的读取操作有效,所以,如果因为某些原因驱动程序在N字节的包中丢失某个字符的话,read(2)调用将会一直等下去.

VTIME可以以十分之一秒为单位指定等待字符输入的时间.如果VTIME设置为0(默认情况),除非open(2)或者fcntl(2)函数设置了NDELAY选项,否则read(2)将会永久得阻塞(等待).

5. 读写串口

设置好串口之后,读写串口就很容易了,把串口当作文件读写就是.

  • 发送数据
1 char  buffer[1024];int    Length;int    nByte;nByte = write(fd, buffer ,Length)

和写入其他设备文件的方式相同,write函数也会返回发送数据的字节数或者在发生错误的时候返回-1.通常,发送数据最常见的错误就是EIO,当调制解调器或者数据链路将Data Carrier Detect(DCD)信号线弄掉了,就会发生这个错误.而且,直至关闭端口这个情况会一直持续.

  • 读取串口数据

使用文件操作read函数读取,如果设置为原始数据模式(Raw Date Mode)传输数据,那么read函数返回的字符数是实际串口收到的字符数,也就是返回从串口输入缓冲区中实际得到的字符的个数.在不能得到数据的情况下,read(2)系统调用就会一直等着,只到有端口上新的字符可以读取或者发生超时或者错误的情况发生.

1 char  buff[1024];int    Len;int  readByte = read(fd,buff,Len);

如果需要read(2)函数迅速返回的话,可以使用操作文件的函数来实现异步读取,如fcntl,或者select等来操作:

1 fcntl(fd, F_SETFL, FNDELAY);

标志FNDELAY可以保证read(2)函数在端口上读不到字符的时候返回0.需要回到正常(阻塞)模式的时候,需要再次在不带FNDELAY标志的情况下调用fcntl(2)函数:

1 fcntl(fd, F_SETFL, 0);

当然,如果你最初就是以O_NDELAY标志打开串口的,你也可在之后使用这个方法改变读取的行为方式.

6. 关闭串口

关闭串口就是关闭文件.

1 close(fd);

关闭串口会将DTR信号线设置成low,这会导致很多调制解调器挂起.

7. 例子

下面是一个简单的读取串口数据的例子,使用了上面定义的一些函数和头文件.

复制代码

 1 /**********************************************************************
 2 代码说明:使用串口二测试的,发送的数据是字符,
 3 但是没有发送字符串结束符号,所以接收到后,后面加上了结束符号。
 4 我测试使用的是单片机发送数据到第二个串口,测试通过。
 5 **********************************************************************/
 6 #define FALSE  -1
 7 #define TRUE   0
 8 /*********************************************************************/
 9 int OpenDev(char *Dev)
10 {
11     int    fd = open( Dev, O_RDWR );         //| O_NOCTTY | O_NDELAY    
12     if (-1 == fd)    
13     {             
14         perror("Can't Open Serial Port");
15         return -1;        
16     }    
17     else    
18         return fd;
19 }
20 int main(int argc, char **argv){
21     int fd;
22     int nread;
23     char buff[512];
24     char *dev  = "/dev/ttyS1"; //串口二
25     fd = OpenDev(dev);
26     set_speed(fd,19200);
27     if (set_Parity(fd,8,1,'N') == FALSE)  {
28         printf("Set Parity Error\n");
29         exit (0);
30     }
31 while (1) //循环读取数据
32 {   
33     while((nread = read(fd, buff, 512))>0)
34     { 
35         printf("\nLen %d\n",nread); 
36         buff[nread+1] = '\0';   
37         printf( "\n%s", buff);   
38     }
39 }
40     //close(fd);  
41     // exit (0);
42 }

本文转自:http://www.ibm.com/developerworks/cn/linux/l-serials/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值