当前位置:文档之家› Socket编程(最新,带例程)c语言

Socket编程(最新,带例程)c语言

Socket编程(最新,带例程)c语言
Socket编程(最新,带例程)c语言

最新版Socket编程,后面带有程序实例,并通过调试,可以直接编译运行;希望对大家有帮助。

网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。Socket也具有一个类似于打开文件的函数调用Socket(),该函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。

什么是Socket

Socket接口是TCP/IP网络的API,Socket接口定义了许多函数或例程,程序员可以用它们来开发TCP/IP网络上的应用程序。要学Internet上的TCP/IP网络编程,必须理解Socket接口。

Socket接口设计者最先是将接口放在Unix操作系统里面的。如果了解Unix系统的输入和输出的话,就很容易了解Socket了。网络的 Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。Socket也具有一个类似于打开文件的函数调用Socket(),该函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。常用的Socket类型有两种:流式Socket (SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。

Socket建立

为了建立Socket,程序可以调用Socket函数,该函数返回一个类似于文件描述符的句柄。socket函数原型为:

int socket(int domain, int type, int protocol);

domain指明所使用的协议族,通常为PF_INET,表示互联网协议族(TCP/IP协议族);type参数指定socket的类型: SOCK_STREAM 或SOCK_DGRAM,Socket 接口还定义了原始Socket(SOCK_RAW),允许程序使用低层协议;protocol通常赋值 "0"。 Socket()调用返回一个整型socket描述符,你可以在后面的调用使用它。

Socket描述符是一个指向内部数据结构的指针,它指向描述符表入口。调用Socket函数时,socket执行体将建立一个Socket,实际上 "建立一个Socket"意味着为一个Socket数据结构分配存储空间。Socket执行体为你管理描述符表。两个网络程序之间的一个网络连接包括五种信息:通信协议、本地协议地址、本地主机端口、远端主机地址和远端协议端口。Socket数据结构中包含这五种信息。

Socket配置

通过socket调用返回一个socket描述符后,在使用socket进行网络传输以前,必须配置该socket。面向连接的socket客户端通过调用Connect函数在socket数据结构中保存本地和远端信息。无连接socket的客户端和服务端以及面向连接socket的服务端通过调用bind函数来配置本地信息。

Bind函数将socket与本机上的一个端口相关联,随后你就可以在该端口监听服务请求。Bind 函数原型为:

int bind(int sockfd,struct sockaddr *my_addr, int addrlen);

Sockfd是调用socket函数返回的socket描述符,my_addr是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针;addrlen常被设置为sizeof(struct sockaddr)。

struct sockaddr结构类型是用来保存socket信息的:

struct sockaddr {

unsigned short sa_family; /* 地址族,AF_xxx */

char sa_data[14]; /* 14 字节的协议地址*/

};

sa_family一般为AF_INET,代表Internet(TCP/IP)地址族;sa_data则包含该socket的IP 地址和端口号。

另外还有一种结构类型:

struct sockaddr_in {

short int sin_family; /* 地址族*/

unsigned short int sin_port; /* 端口号*/

struct in_addr sin_addr; /* IP地址*/

unsigned char sin_zero[8]; /* 填充0 以保持与struct sockaddr同样大小*/

};

这个结构更方便使用。sin_zero用来将sockaddr_in结构填充到与struct sockaddr同样的长度,可以用bzero()或memset()函数将其置为零。指向sockaddr_in 的指针和指向sockaddr的指针可以相互转换,这意味着如果一个函数所需参数类型是sockaddr时,你可以在函数调用的时候将一个指向sockaddr_in的指针转换为指向sockaddr的指针;或者相反。

使用bind函数时,可以用下面的赋值实现自动获得本机IP地址和随机获取一个没有被占用的端口号:

my_addr.sin_port = 0; /* 系统随机选择一个未被使用的端口号*/

my_addr.sin_addr.s_addr = INADDR_ANY; /* 填入本机IP地址*/

通过将my_addr.sin_port置为0,函数会自动为你选择一个未占用的端口来使用。同样,通过将my_addr.sin_addr.s_addr置为INADDR_ANY,系统会自动填入本机IP地址。

注意在使用bind函数时需要将sin_port和sin_addr转换成为网络字节优先顺序;而sin_addr 则不需要转换。

计算机数据存储有两种字节优先顺序:高位字节优先和低位字节优先。Internet上数据以高位字节优先顺序在网络上传输,所以对于在内部是以低位字节优先方式存储数据的机器,在Internet上传输数据时就需要进行转换,否则就会出现数据不一致。

下面是几个字节顺序转换函数:

·htonl():把32位值从主机字节序转换成网络字节序

·htons():把16位值从主机字节序转换成网络字节序

·ntohl():把32位值从网络字节序转换成主机字节序

·ntohs():把16位值从网络字节序转换成主机字节序

Bind()函数在成功被调用时返回0;出现错误时返回"-1"并将errno置为相应的错误号。需要注意的是,在调用bind函数时一般不要将端口号置为小于1024的值,因为1到1024是保留端口号,你可以选择大于1024中的任何一个没有被占用的端口号。

连接建立

面向连接的客户程序使用Connect函数来配置socket并与远端服务器建立一个TCP连接,其函数原型为:

int connect(int sockfd, struct sockaddr *serv_addr,int addrlen); Sockfd 是socket函数返回的socket描述符;serv_addr是包含远端主机IP地址和端口号的指针;addrlen是远端地质结构的长度。 Connect函数在出现错误时返回-1,并且设置errno为相应的错误码。

进行客户端程序设计无须调用bind(),因为这种情况下只需知道目的机器的IP地址,而客户通过哪个端口与服务器建立连接并不需要关心,socket执行体为你的程序自动选择一个未被占用的端口,并通知你的程序数据什么时候到打断口。

Connect函数启动和远端主机的直接连接。只有面向连接的客户程序使用socket 时才需要将此socket与远端主机相连。无连接协议从不建立直接连接。面向连接的服务器也从不启动一个连接,它只是被动的在协议端口监听客户的请求。Listen函数使socket处于被动的监听模式,并为该socket建立一个输入数据队列,将到达的服务请求保存在此队列中,直到程序处理它们。

int listen(int sockfd, int backlog);

Sockfd 是Socket系统调用返回的socket 描述符;backlog指定在请求队列中允许的最大请求数,进入的连接请求将在队列中等待accept()它们(参考下文)。Backlog对队列中等待服务的请求的数目进行了限制,大多数系统缺省值为20。如果一个服务请求到来时,输入队列已满,该socket将拒绝连接请求,客户将收到一个出错信息。

当出现错误时listen函数返回-1,并置相应的errno错误码。

accept()函数让服务器接收客户的连接请求。在建立好输入队列后,服务器就调用accept函数,然后睡眠并等待客户的连接请求。

int accept(int sockfd, void *addr, int *addrlen);

sockfd是被监听的socket描述符,addr通常是一个指向sockaddr_in变量的指针,该变量用来存放提出连接请求服务的主机的信息(某台主机从某个端口发出该请求);addrten通常为一个指向值为sizeof(struct sockaddr_in)的整型指针变量。出现错误时accept函数返回-1并置相应的errno值。

首先,当accept函数监视的 socket收到连接请求时,socket执行体将建立一个新的socket,执行体将这个新socket和请求连接进程的地址联系起来,收到服务请求的初始socket仍可以继续在以前的 socket上监听,同时可以在新的socket描述符上进行数据传输操作。

数据传输

Send()和recv()这两个函数用于面向连接的socket上进行数据传输。

Send()函数原型为:

int send(int sockfd, const void *msg, int len, int flags);

Sockfd是你想用来传输数据的socket描述符;msg是一个指向要发送数据的指针;Len是以字节为单位的数据的长度;flags一般情况下置为0(关于该参数的用法可参照man手册)。

Send()函数返回实际上发送出的字节数,可能会少于你希望发送的数据。在程序

中应该将send()的返回值与欲发送的字节数进行比较。当send()返回值与len 不匹配时,应该对这种情况进行处理。

char *msg = "Hello!";

int len, bytes_sent;

……

len = strlen(msg);

bytes_sent = send(sockfd, msg,len,0);

……

recv()函数原型为:

int recv(int sockfd,void *buf,int len,unsigned int flags);

Sockfd是接受数据的socket描述符;buf 是存放接收数据的缓冲区;len是缓冲的长度。Flags也被置为0。Recv()返回实际上接收的字节数,当出现错误时,返回-1并置相应的errno值。

Sendto()和recvfrom()用于在无连接的数据报socket方式下进行数据传输。由于本地socket并没有与远端机器建立连接,所以在发送数据时应指明目的地址。sendto()函数原型为:

int sendto(int sockfd, const void *msg,int len,unsigned int flags,const struct sockaddr *to, int tolen);

该函数比send()函数多了两个参数,to表示目地机的IP地址和端口号信息,而tolen常常被赋值为sizeof (struct sockaddr)。Sendto 函数也返回实际发送的数据字节长度或在出现发送错误时返回-1。

Recvfrom()函数原型为:

int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *from,int *fromlen);

from是一个struct sockaddr类型的变量,该变量保存源机的IP地址及端口号。fromlen常置为sizeof (struct sockaddr)。当recvfrom()返回时,fromlen

包含实际存入from中的数据字节数。Recvfrom()函数返回接收到的字节数或当出现错误时返回-1,并置相应的errno。

如果你对数据报socket调用了connect()函数时,你也可以利用send()和recv()进行数据传输,但该socket仍然是数据报socket,并且利用传输层的UDP服务。但在发送或接收数据报时,内核会自动为之加上目地和源地址信息。

结束传输

当所有的数据操作结束以后,你可以调用close()函数来释放该socket,从而停止在该socket上的任何数据操作:

close(sockfd);

你也可以调用shutdown()函数来关闭该socket。该函数允许你只停止在某个方向上的数据传输,而一个方向上的数据传输继续进行。如你可以关闭某socket 的写操作而允许继续在该socket上接受数据,直至读入所有数据。

int shutdown(int sockfd,int how);

Sockfd是需要关闭的socket的描述符。参数 how允许为shutdown操作选择以下几种方式:

·0-------不允许继续接收数据

·1-------不允许继续发送数据

·2-------不允许继续发送和接收数据,

·均为允许则调用close ()

shutdown在操作成功时返回0,在出现错误时返回-1并置相应errno。

Socket编程实例

代码实例中的服务器通过socket连接向客户端发送字符串"Hello, you are connected!"。只要在服务器上运行该服务器软件,在客户端运行客户软件,客户端就会收到该字符串。

该服务器软件代码如下:

#include

#include

#include

#include

#include

#include

#include

#include

#define SERVPORT 3333 /*服务器监听端口号 */

#define BACKLOG 10 /* 最大同时连接请求数 */

main()

{

int sockfd,client_fd; /*sockfd:监听socket;client_fd:数据传输socket */

struct sockaddr_in my_addr; /* 本机地址信息 */

struct sockaddr_in remote_addr; /* 客户端地址信息 */

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

perror( "socket创建出错!"); exit(1);

}

my_addr.sin_family=AF_INET;

my_addr.sin_port=htons(SERVPORT);

my_addr.sin_addr.s_addr = INADDR_ANY;

bzero( &(my_addr.sin_zero),8);

if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) == -1) {

perror( "bind出错!");

exit(1);

}

if (listen(sockfd, BACKLOG) == -1) {

perror( "listen出错!");

exit(1);

}

while(1) {

sin_size = sizeof(struct sockaddr_in);

if ((client_fd = accept(sockfd, (struct sockaddr *) &remote_addr,

&sin_size)) == -1) {

perror( "accept出错");

continue;

}

printf( "received a connection from %s\n",

inet_ntoa(remote_addr.sin_addr));

if (!fork()) { /* 子进程代码段 */

if (send(client_fd, "Hello, you are connected!\n", 26, 0) == -1) perror( "send出错!");

close(client_fd);

exit(0);

}

close(client_fd);

}

}

}

服务器的工作流程是这样的:首先调用socket函数创建一个Socket,然后调用bind函数将其与本机地址以及一个本地端口号绑定,然后调用 listen在相应的socket上监听,当accpet接收到一个连接服务请求时,将生成一个新的socket。服务器显示该客户机的IP地址,并通过新的socket向客户端发送字符串"Hello,you are connected!"。最后关闭该socket。

代码实例中的fork()函数生成一个子进程来处理数据传输部分,fork()语句对于子进程返回的值为0。所以包含fork函数的if语句是子进程代码部分,它与if语句后面的父进程代码部分是并发执行的。

客户端程序代码如下:

#include

#include

#include

#include

#include

#include

#include

#include

#define SERVPORT 3333

#define MAXDATASIZE 100 /*每次最大数据传输量 */

main(int argc, char *argv[]){

int sockfd, recvbytes;

char buf[MAXDATASIZE];

struct hostent *host;

struct sockaddr_in serv_addr;

if (argc < 2) {

fprintf(stderr,"Please enter the server's hostname!\n");

exit(1);

}

if((host=gethostbyname(argv[1]))==NULL) {

herror("gethostbyname出错!");

exit(1);

}

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){

perror("socket创建出错!");

exit(1);

}

serv_addr.sin_family=AF_INET;

serv_addr.sin_port=htons(SERVPORT);

serv_addr.sin_addr = *((struct in_addr *)host- >h_addr);

bzero( &(serv_addr.sin_zero),8);

if (connect(sockfd, (struct sockaddr *) &serv_addr, \

sizeof(struct sockaddr)) == -1) {

perror("connect出错!");

exit(1);

}

if ((recvbytes=recv(sockfd, buf, MAXDATASIZE, 0)) ==-1) {

perror("recv出错!");

exit(1);

}

buf[recvbytes] = '\0';

printf( "Received: %s",buf);

close(sockfd);

}

客户端程序首先通过服务器域名获得服务器的IP地址,然后创建一个socket,调用connect函数与服务器建立连接,连接成功之后接收从服务器发送过来的数据,最后关闭socket。

函数gethostbyname()是完成域名转换的。由于IP地址难以记忆和读写,所以为了方便,人们常常用域名来表示主机,这就需要进行域名和IP地址的转换。函数原型为:

struct hostent *gethostbyname(const char *name);

函数返回为hosten的结构类型,它的定义如下:

struct hostent {

char *h_name; /* 主机的官方域名 */

char **h_aliases; /* 一个以NULL结尾的主机别名数组 */

int h_addrtype; /* 返回的地址类型,在Internet环境下为AF-INET */

int h_length; /* 地址的字节长度 */

char **h_addr_list; /* 一个以0结尾的数组,包含该主机的所有地址*/

};

#define h_addr h_addr_list[0] /*在h-addr-list中的第一个地址*/

当 gethostname()调用成功时,返回指向struct hosten的指针,当调用失败时返回-1。当调用gethostbyname时,你不能使用perror()函数来输出错误信息,而应该使用herror()函数来输出。

无连接的客户/服务器程序的在原理上和连接的客户/服务器是一样的,两者的区别在于无连接的客户/服务器中的客户一般不需要建立连接,而且在发送接收数据时,需要指定远端机的地址。

阻塞和非阻塞

阻塞函数在完成其指定的任务以前不允许程序调用另一个函数。例如,程序执行一个读数据的函数调用时,在此函数完成读操作以前将不会执行下一程序语句。当服务器运行到accept语句时,而没有客户连接服务请求到来,服务器就会停止在accept语句上等待连接服务请求的到来。这种情况称为阻塞(blocking)。而非阻塞操作则可以立即完成。比如,如果你希望服务器仅仅注意检查是否有客户在等待连接,有就接受连接,否则就继续做其他事情,则可以通过将Socket 设置为非阻塞方式来实现。非阻塞socket在没有客户在等待时就使accept调用立即返回。

#include

#include

……

sockfd = socket(AF_INET,SOCK_STREAM,0);

fcntl(sockfd,F_SETFL,O_NONBLOCK);

……

通过设置socket为非阻塞方式,可以实现 "轮询"若干Socket。当企图从一个没有数据等待处理的非阻塞Socket读入数据时,函数将立即返回,返回值为-1,并置errno值为EWOULDBLOCK。但是这种"轮询"会使CPU处于忙等待方式,从而降低性能,浪费系统资源。而调用 select()会有效地解决这个问题,它允许你把进程本身挂起来,而同时使系统内核监听所要求的一组文件描述符的任何活动,只要确认在任何被监控的文件描述符上出现活动,select()调用将返回指示该文件描述符已准备好的信息,从而实现了为进程选出随机的变化,而不必由进程本身对输入进行测试而浪费 CPU开销。Select函数原型为:

int select(int numfds,fd_set *readfds,fd_set *writefds,

fd_set *exceptfds,struct timeval *timeout);

其中readfds、writefds、exceptfds分别是被select()监视的读、写和异常处理的文件描述符集合。如果你希望确定是否可以从标准输入和某个socket描述符读取数据,你只需要将标准输入的文件描述符0和相应的sockdtfd加入到readfds集合中;numfds的值是需要检查的号码最高的文件描述符加1,这个例子中numfds的值应为sockfd+1;当select返回时,readfds将被修改,指示某个文件描述符已经准备被读取,你可以通过FD_ISSSET()来测试。为了实现fd_set中对应的文件描述符的设置、复位和测试,它提供了一组宏:

FD_ZERO(fd_set *set)----清除一个文件描述符集;

FD_SET(int fd,fd_set *set)----将一个文件描述符加入文件描述符集中;FD_CLR(int fd,fd_set *set)----将一个文件描述符从文件描述符集中清除;FD_ISSET(int fd,fd_set *set)----试判断是否文件描述符被置位。

Timeout参数是一个指向struct timeval类型的指针,它可以使select()在等待timeout长时间后没有文件描述符准备好即返回。struct timeval数据结构为:

struct timeval {

int tv_sec; /* seconds */

int tv_usec; /* microseconds */

};

POP3客户端实例

下面的代码实例基于POP3的客户协议,与邮件服务器连接并取回指定用户帐号的邮件。与邮件服务器交互的命令存储在字符串数组POPMessage中,程序通过一个do-while循环依次发送这些命令。

#include

#include

#include

#include

#include

#include

#include

#include

#define POP3SERVPORT 110

#define MAXDATASIZE 4096

main(int argc, char *argv[]){

int sockfd;

struct hostent *host;

struct sockaddr_in serv_addr;

char *POPMessage[]={

"USER userid\r\n",

"PASS password\r\n",

"STAT\r\n",

"LIST\r\n",

"RETR 1\r\n",

"DELE 1\r\n",

"QUIT\r\n",

NULL

};

int iLength;

int iMsg=0;

int iEnd=0;

char buf[MAXDATASIZE];

if((host=gethostbyname("your.server"))==NULL) {

perror("gethostbyname error");

exit(1);

}

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){

perror("socket error");

exit(1);

}

serv_addr.sin_family=AF_INET;

serv_addr.sin_port=htons(POP3SERVPORT);

serv_addr.sin_addr = *((struct in_addr *)host->h_addr);

bzero(&(serv_addr.sin_zero),8);

if (connect(sockfd, (struct sockaddr *)&serv_addr,sizeof(struct sockaddr))==-1){

perror("connect error");

exit(1);

}

do {

send(sockfd,POPMessage[iMsg],strlen(POPMessage[iMsg]),0);

printf("have sent: %s",POPMessage[iMsg]);

iLength=recv(sockfd,buf+iEnd,sizeof(buf)-iEnd,0);

iEnd+=iLength;

buf[iEnd]='\0';

printf("received: %s,%d\n",buf,iMsg);

iMsg++;

} while (POPMessage[iMsg]);

close(sockfd);

}

Tcl语言基础教程

Tcl语言参考 Tcl("Tool Command Language",即工具命令语言;Tcl念作“踢叩” "tickle" )是一种易学易用易于扩展的脚本语言,实际上包 含了两个部分:一个语言和一个库。 首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些交互程序如文本编辑器、调试器和shell。它有一个简单 的语法和很强可扩充性,Tcl可以创建新的过程以增强其内建命令的能力。 其次,Tcl是一个库包,可以被嵌入应用程序,Tcl的库包含了一个分析器、用于执行内建命令的例程和可以使你扩充 (定义新的过程)的库函数。应用程序可以产生Tcl命令并执行,命令可以由用户产生,也可以从用户接口的一个输入中读 取(按钮或菜单等)。 Tcl和其他编程语言例如C不同,它是一种解释语言而非编译语言。Tcl程序由一系列Tcl 命令组成,在运行时由Tcl解释 器解释运行。 Tcl有大量的用C/C++编写的扩展用于提供Tcl本身不具有的功能。其中使用最广泛的扩展是TK,TK提供了各种OS平台下 的图形用户界面GUI(连强大的Python语言都不单独提供自己的GUI,而是提供接口适配到TK上)。另一个流行的扩展包是Exp- ect,它提供了通过终端自动执行命令的能力,例如passwd, ftp, telnet等命令驱动的外壳。

一、Tcl程序基本结构 1、基本语法 Tcl有类似于shell的语法,一条Tcl的命令串包含了一条或多条命令用换行符或分号来隔开,而每一条命令包含了一个 域(field)的集合,域使用空白(空格或TAB)分开的,第一个域是一个命令的名字,其它的是作为参数来传给它。 Tcl解释器对一个命令的求值过程分为两部分:分析和执行。在分析阶段,Tcl 解释器运用规则识别出命令并把命令分 成一个个独立的单词,同时进行必要的置换(substitution);在执行阶段,Tcl 解释器会把第一个单词当作命令名,并查看这 个命令是否有定义,如果有定义就激活这个命令对应的C/C++过程,并把所有的单词作为参数传递给该命令过程,让命令过 程进行处理。 Tcl的命令名可以是内建的命令也可以是用户建的新命令,在应用程序中可用函数Tcl_CreateCommand来创建新的命令。 所有的参数作为字符串来传递,命令自己会按其所需来解释的参数的。 另外关于Tcl的注释有一个特殊的要求:'#'必须出现在Tcl解释器期望命令的第一个字符出现的地方,才被当作注释。 例如: set a 100 # Not a comment

TCL语言及其文件的认识、理解和编辑

TCL语言及其文件的认识、理解和编辑 欢迎大家指正和补充。 Tcl语法简介 Tcl是用于工具命令语言的一个解释器。它由作为基本命令解释器嵌入到工具(比如编辑器、调试器等)中的一个库包组成。Tcl提供了(a)用于简单的文本命令语言的分析器,(b)一组内置的实用命令,和(c)一个C 接口,工具通过它用特定于工具的命令增加内置命令。Tcl在与窗口组件库整合的时候特别有吸引力:它通过了提供变量、过程、表达式等机制增进了组件的可编程性;它允许用户编程组件的外观和动作二者;并且它在交互式程序之间提供一个简单但强力的通信机制 作为一种脚本语言,Tcl具有简单的语法 Tcl/Tk 的发明人John Ousterhout 教授在八十年代初,是伯克利大学的教授。在其教学过程中,他发现在集成电路CAD 设计中,很多时间是花在编程建立测试环境上。并且,环境一旦发生了变化,就要重新修改代码以适应。这种费力而又低效的方法,迫使Ousterhout 教授力图寻找一种新的编程语言,它即要有好的代码可重用性,又要简单易学,这样就促成了Tcl (Tool Command Language) 语言的产生。 Tcl最初的构想的是希望把编程按照基于组件的方法(component approach),即与其为单个的应用程序编写成百上千行的程序代码,不如寻找一个种方法将程序分割成一个个小的, 具备一定“完整”功能的,可重复使用的组件。这些小的组件小到可以基本满足一些独立的应用程序的需求,其它部分可由这些小的组件功能基础上生成。不同的组件有不同的功能,用于不同的目的。并可为其它的应用程序所利用。当然, 这种语言还要有良好的扩展性, 以便用户为其增添新的功能模块。最后,需要用一种强的,灵活的“胶水”把这些组件“粘”合在一起, 使各个组件之间可互相“通信”,协同工作。程序设计有如拼图游戏一样,这种设计思想与后来的Java 不谋而合。终于在1988 年的春天, 这种强大灵活的胶水- Tcl语言被发明出来了。 按照Ousterhout 教授的定义,Tcl是一种可嵌入的命令脚本化语言(Command Script Language)。“可嵌入”是指把很多应用有效,无缝地集成在一起。“命令”是指每一条Tcl 语句都可以理解成命令加参数的形式: 命令[参数1] [参数2] [参数3] [参数4] ...... [参数N] 脚本化是指Tcl为特殊的,特定的任务所设计。但从现在角度看,可以说Tcl是一种集C 语言灵活强大的功能与BASIC 语言易学高效的风格于一身的通用程序设计语言。 Tk (Tool Kit) 是基于Tcl的图形程序开发工具箱, 是Tcl的重要扩展部分。Tk 隐含许多C/C++ 程序员需要了解的程序设计细节, 可快速地开发基于图形界面Windows 的程序。据称, 用Tcl/Tk 开发一个简单的GUI 应用程序只需几个小时, 比用C/C++ 要提高效率十倍。需要指明的是这里所说的“窗口”是指Tcl定义的窗口,与X-Windows 与MS Windows 的定义有所不同,但它可完美地运行在以上两个系统上。 Tcl代表了“tool command language - 工具命令语言”。它由一个库包组成,程序可以把它用作自己的命令语言的基础。Tcl的开发由两项观察所推动。第一项观察是,通用可编程命令语言通过允许用户用命令语言写程序来扩展工具的内置设施,从而扩大了工具的能力。在强力的命令语言之中最众所周知的例子是UNIX shell[5] 和Emacs 编辑器[8]。在各自情况下,出现的有着不同寻常能力的计算环境,在很大程度上是因为能获得可编程的命令语言。第二个促成它的观察是交互式应用正在增长。在1970 年代晚期和1980 年代早期的分时环境中,几乎所有的程序都是面向批处理的。典型的使用交互式的命令shell 来调用它们。

TCL脚本实例解读

TCL脚本实例解读 作者:杨帆、老卢 前言 Sigma的这段日子在技术方面感觉提高的方面可能就是脚本的编写吧,我感觉写一个可用的脚本,并不一定非的在于你对脚本有了多了解之后,然后再去实现一个切合实际的脚本,最主要是思路,当你对所需要使用的脚本工具有一定的理解(如:TCL),在一个实际环境,首先能有个明确的想法,想实现个具体的什么东西,怎么样的思路可以实现,大脑里具备了这些条件,就可以尝试去写一些脚本。当然了,在实现的过程中肯定会遇到这样或者那样的问题,但一般来说,基本都是一些对脚本语法以及命令不熟悉的原因造成,这些问题很好解决,可以跟熟悉脚本的同事讨论,来帮你解决当时的问题,所以,千万不要因为还没有开始,就将脚本看得非常困难,导致自己一直无法迈出第一步,其实有些东西还是比较容易实现的。所以在此将我写的几个脚本在此解读解读。 文档目的 这篇文档中所附带的脚本,主要是根据Sigma这边搭建的系统测试环境而撰写出来的,脚本内容可能与今后Sigma公司为我们所开发的系统测试脚本无关,当撰写完这几个脚本之后,各人感觉有些东西还是比较有价值的,因此本人将此脚本撰写为文档,将这些东西共享出来供大家分享、借鉴、参考,相信看完这篇文档,因该会提供很多切合实际测试的一些脚本开发思路。还有,这篇文档并非一篇解释TCL命令的文档,有许多脚本中的相关命令不熟悉的地方需要查找其它资料,部分命令只做了解释或者介绍。 感谢!:) 这些脚本的撰写过程中感谢小康同学与小井同学的帮助(很多地方错误的查找、以及提供了一些解决关键问题的命令,如果没有他们的帮助,这个脚本完成的难度就大了,有很多也是他们的功劳) 环境介绍 这里提到的环境主要介绍的是系统测试的物理网络TOP环境与逻辑网络TOP环境,因为脚本里面的内容跟这个具体环境有关: 物理网络TOP,物理网络TOP所描述的实际是所有测试PC与DUT连接的物理

TCL语言.

TCL语言 Tcl(最早称为“工具命令语言”"Tool Command Language", 但是目前已经不是这个含义,不过我们仍然称呼它为TCL)是一种脚本语言。由John Ousterhout创建。TCL很好学,功能很强大。TCL经常被用于快速原型开发,脚本编程,GUI 和测试等方面。TCL念作“踢叩” "tickle". Tcl的特性包括: * 任何东西都是一条命令,包括语法结构(for, if等)。 * 任何事物都可以重新定义和重载。 * 所有的数据类型都可以看作字符串。 * 语法规则相当简单 * 提供事件驱动给Socket和文件。基于时间或者用户定义的事件也可以。 * 动态的域定义。 * 很容易用C, C++,或者Java扩展。 * 解释语言,代码能够动态的改变。 * 完全的Unicode支持。 * 平台无关。Win32, UNIX, Mac上都可以跑。 * 和Windows的GUI紧密集成。Tk * 代码紧凑,易于维护。 TCL本身不提供面向对象的支持。但是语言本身很容易扩展到支持面向对象。许多C语言扩展都提供面向对象能力,包括XOTcl, Incr Tcl 等。另外SNIT扩展本身就是用TCL写的。 使用最广泛的TCL扩展是TK。TK提供了各种OS平台下的图形用户界面GUI。连强大的Python语言都不单独提供自己的GUI,而是提供接口适配到TK上。另一个流行的扩展包是Expect. Expect提供了通过终端自动执行命令的能力,例如(pass wd, ftp, telnet等命令驱动的外壳). 下面是TCL程序的例子: #!/bin/sh # next line restarts using tclsh in path \ exec tclsh ${1+"$@"} # echo server that can handle multiple # simultaneous connections. proc newConnection { sock addr port } { # client connections will be handled in # line-buffered, non-blocking mode fconfigure $sock -blocking no -buffering line # call handleData when socket is readable fileevent $sock readable [ list handleData $sock ] } proc handleData {

tcl脚本进行二次开发

HyperMesh中利用Tcl脚本进行二次开发 杨国雄 上海世科嘉车辆技术有限公司

HyperMesh中利用Tcl脚本进行二次开发 Further Develop by Tcl Script Based on HyperMesh 杨国雄 (上海世科嘉车辆技术有限公司) 摘要:当代企业发展的关键是创新,本文通过对HyperMesh软件进来二次开发的两个实例—频响分析流程订制和通过Comps名自动定义单元属性,研讨了通过HyperMesh软件对企业CAE分析流程进行简化,标准化,人性化的可能性。 关键字:Tcl,二次开发,HyperMesh Abstract:Innovation is the key of contemporary enterprise's development. In this paper, 2 examples(customized frequency analysis process and automatic definition of element properties via comps name)were made by further developed of HyperMesh. The possibility of CAE analysis process be simplified, standardized and humanized with HyperMesh software was also discussed. Keyword:Tcl, Further Develop,HyperMesh 1 概述 随着各个行业对CAE技术应用的深入,企业对规范化分析流程,简化前处理等各个方面提出了需求。HyperMesh是一款功能强大的有限元前处理软件,同时还具有丰富的二次开发能力。通过二次开发为企业更好的利用HyperMesh软件提供了可能性。 2 HyperMesh二次开发简介 HyperMesh二次开发主要包括了2个层次的内容——宏命令和Tcl/Tk脚本。宏命令主要功能是定义面板按钮及对Tcl脚本的调用。Tcl/Tk脚本命令可以自定义各类窗口,程序的流程化控制,宏命令、Tcl脚本和C语言程序的关系如图1所示。本文主要讨论Tcl脚本的编写。

TCL语言基础资料

TCL语言基础资料 一脚本语言详细介绍 21世纪的高级编程语言 摘要: Perl和Tcl等脚本语言代表一种与c或JavaTM 为代表的系统程序设计语言完全不同的编程形式。脚本语言为"胶着"应用程序而设计,它使用无类型方法来实现高级编程和比系统程序设计语言更快的发展应用。计算机速度的增长和混合应用的改变使脚本语言在今后的应用中越来越重要。 关键字: 组件框架,面向对象编程,脚本,强类型,系统编程 1.简介 在过去的十五年里,人们编写计算机程序的方法

发生了根本的转变。这种转变是从c或c++等系统程序设计语言到Perl或Tcl等脚本语言的过渡。虽然很多人参与了转变,却很少有人意识到它的发生,更不用说知道为什么会发生。这篇文章是我关于为什么在下个世纪脚本语言可以比系统程序设计语言更好的处理许多编程工作的一点看法。 与系统程序设计语言相比,不同的脚本语言为不同的工作而设计,这导致了语言间的根本不同。系统程序设计语言起源于像内存字等最初期的计算机元素,它为建立数据结构和算法而创建。相反的,脚本语言为胶着而设计:他们假设已经存在一套强大的组件,而它主要是把组件连在一起。系统程序设计语言使用强类型定义来帮助处理复杂事务,而脚本语言使用无类型定义来简化组件间的联系,并提供快速应用开发. 脚本语言和系统程序设计语言互为补充,并且二十世纪六十年代以来的大多数主要的计算机平台都同时提供这两种类型的语言。这些语言在组件框架中有着典型的应用:组件由系统程序设计语言创建,并由脚本语言组合在一起。然而,速度更快的机器,

更好的脚本语言,图形用户界面和组件构造重要性的不断提高,因特网的发展等发展趋势大大提高了脚本语言的应用。在今后的十年中,这种趋势将继续,而且越来越多的完全使用脚本语言和系统程序设计语言书写的应用程序将主要用来创建组件。 2.系统程序设计语言 为了理解脚本语言和系统程序设计语言的不同,最好先了解一下系统程序设计语言是如何发展的.系统程序设计语言是作为除汇编语言外的另一种选择而引入的.在汇编语言里,实际上机器的每一个细节都被反映在程序里.每个状态代表一个简单的机器指令,而程序员必须处理像寄存器分配和程序调用顺序等低层细节.因此,用汇编语言编写和维持大型程序是很困难的. 真的不掉线吗??、???????????? 二十世纪五十年代后期像Lisp,Fortran和Algol等高层语言开始出现.这些语言里的状态和机器指令不再完全一致,编译程序把过程程序中的每个状

Tcl脚本语言教程

Tcl教程 TCL语法 ■脚本、命令和单词符号 (2) ■置换(substitution) (2) ■注释 (5) 变量 ■简单变量 (5) ■数组 (6) ■相关命令 (6) 表达式 ■操作数 (7) ■运算符和优先级 (7) ■数学函数 (8) List ■list命令 (10) ■concat命令 (10) ■lindex命令 (11) ■llength命令 (11) ■linsert命令 (11) ■lreplace命令 (11) ■lrange 命令 (11) ■lappend命令 (12) ■lsearch 命令 (12) ■lsort命令 (13) ■split命令 (13) ■join命令 (13) 控制流 ■if命令 (13) ■循环命令:while 、for、foreach (14) ■eval命令 (15) ■source命令 (16) 过程(procedure) ■过程定义和返回值 (16) ■局部变量和全局变量 (17) ■缺省参数和可变个数参数 (17) ■引用:upvar (18) 字符串操作 ■format命令 (19) ■scan命令 (20) 1

■regexp命令 ■regsub命令 ■string命令 文件访问 ■文件名 ■基本文件输入输出命令 ■随机文件访问 ■当前工作目录 ■文件操作和获取文件信息 错误和异常 ■错误 ■从TCL脚本中产生错误 ■使用catch捕获错误 ■其他异常 深入TCL ■查询数组中的元素 ■info命令 TCL语法> 脚本、命令和单词符号 一个TCL脚本可以包含一个或多个命令。命令之间必须用换行符或分号隔开,下面的两个脚本都是合法的: set a 1 set b 2 或 set a 1;set b 2 TCL的每一个命令包含一个或几个单词,第一个单词代表命令名,另外的单词则是这个命令的参数,单词之间必须用空格或TAB键隔开。 TCL解释器对一个命令的求值过程分为两部分:分析和执行。在分析阶段,TCL 解释器运用规则把命令分成一个个独立的单词,同时进行必要的置换(substitution);在执行阶段,TCL 解释器会把第一个单词当作命令名,并查看这个命令是否有定义,如果有定义就激活这个命令对应的C/C++过程,并把所有的单词作为参数传递给该命令过程,让命令过程进行处理。 TCL语法> 置换(substitution) 注:在下面的所有章节的例子中,'%'为TCL的命令提示符,输入命令回车后,TCL会在接着的一行输出命令执行结果。'//'后面是我自己加上的说明,不是例子的一部分。 TCL解释器在分析命令时,把所有的命令参数都当作字符串看待,例如: 2

DDL,DML,DCL,TCL四种语言的简介

DDL,DML,DCL,TCL四种语言的简介 1.DDL(Data Definition Language)数据库定义语言 statements are used to define the database structure or schema. DDL是SQL语言的四大功能之一。 用于定义数据库的三级结构,包括外模式、概念模式、内模式及其相互之间的映像,定义数据的完整性、安全控制等约束 DDL不需要commit. CREATE ALTER DROP TRUNCATE COMMENT RENAME 2.DML(Data Manipulation Language)数据操纵语言 statements are used for managing data within schema objects. 由DBMS提供,用于让用户或程序员使用,实现对数据库中数据的操作。 DML分成交互型DML和嵌入型DML两类。 依据语言的级别,DML又可分成过程性DML和非过程性DML两种。 需要commit. SELECT INSERT UPDATE DELETE MERGE CALL EXPLAIN PLAN LOCK TABLE 3.DCL(Data Control Language)数据库控制语言授权,角色控制等GRANT 授权 REVOKE 取消授权 4.TCL(Transaction Control Language)事务控制语言 SAVEPOINT 设置保存点 ROLLBACK 回滚 SET TRANSACTION SQL主要分成四部分: (1)数据定义。(SQL DDL)用于定义SQL模式、基本表、视图和索引的创建和撤消操作。 (2)数据操纵。(SQL DML)数据操纵分成数据查询和数据更新两类。数据更新又分成插入、删除、和修改三种操作。

TCL脚本语言-14-输入输出系统

输入输出系统 输入和输出相比大家都不陌生。说起它,我就想起来大学第一次写Pascal程序的时候,总要写出这样的代码: Program Test(input,output); Begin Write(‘Hello,World!’); End. 老实说,第一行的input和output两个参数让我迷惑了很久,一直都不明白它们的用途。后来才慢慢的知道它们叫做输入和输出。 输入和输出总是和文件系统紧密相连。现代操作系统中,所有的设备几乎都被抽象成文件系统。但是不同操作系统下文件系统格式不同,例如Unix和Windows、MAC的目录等都有一定的差异。好在TCL语言比较好的解决了这个问题。本章节我们会详细的介绍如何在TCL中操作文件系统以及读写文件。 操作文件系统 TCL中能够非常方便的操作文件、目录。包括:查询和设置文件属性、复制、删除以及路径名字的操作等。所有这些都是通过一个file命令来完成,其语法都非常简单,所以我们这里只是按照分类,列举出该命令的各种用法: 文件属性操作 命令用法描述 file atime name ?time? 返回文件name最后被读取的时间;该命令在FAT文 件系统上无效(返回数据可能不正确); file mtime name ?time? 设置或者修改文件name的最后被修改时间。time参 数表示1970/1/1到现在的秒。设置最后修改时间,和 那个著名的touch命令完成类似的功能; file attributes name file attributes name ?opt? file attributes name ?opt vla? ?opt val?... 查询或者设置文件的属性。第一个命令查询所有的属性;第二个命令查询指定的属性;第三个设置属性的值。 file executable name 看看这个文件是否是可执行的,是就返回1;

Tcl用法详述

T C L用法祥述 一TCL语法 1 脚本、命令和单词符号 一个TCL脚本可以包含一个或多个命令。命令之间必须用换行符或分号隔开,下面的两个脚本都是合法的: set a 1 set b 2 或 set a 1;set b 2 TCL的每一个命令包含一个或几个单词,第一个单词代表命令名,另外的单词则是这个命令的参数,单词之间必须用空格或TAB键隔开。 TCL解释器对一个命令的求值过程分为两部分:分析和执行。在分析阶段,TCL 解释器运用规则把命令分成一个个独立的单词,同时进行必要的置换(substitution);在执行阶段,TCL 解释器会把第一个单词当作命令名,并查看这个命令是否有定义,如果有定义就激活这个命令对应的C/C++过程,并把所有的单词作为参数传递给该命令过程,让命令过程进行处理。 2 置换(substitution) 注:在下面的所有章节的例子中,'%'为TCL的命令提示符,输入命令回车后,TCL会在接着的一行输出命令执行结果。'//'后面是我自己加上的说明,不是例子的一部分。 TCL解释器在分析命令时,把所有的命令参数都当作字符串看待,例如: %set x 10 //定义变量x,并把x的值赋为10 10 %set y x+100 //y的值是x+100,而不是我们期望的110 x+100 上例的第二个命令中,x被看作字符串x+100的一部分,如果我们想使用x的值'10' ,就必须告诉TCL解释器:我们在这里期望的是变量x的值,而非字符'x'。怎么告诉TCL解释器呢,这就要用到TCL语言中提供的置换功能。 TCL提供三种形式的置换:变量置换、命令置换和反斜杠置换。每种置换都会导致一个或多个单词本身被其他的值所代替。置换可以发生在包括命令名在内的每一个单词中,而且置换可以嵌套。 1) 变量置换(variable subtitution)

TCL培训教程(全)

. Tcl编程简介(一) 简介 Tcl是一种很通用的脚本语言,它几乎在所有的平台上都可以解释运行,功能强大。是tool command language的缩写,发音为 "tickle”,实际上包含了两个部分:一个语言和一个库。 首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。它有一个简单的语法和很强可扩充性,Tcl可以创建新的过程以增强其内建命令的能力。 其次,Tcl是一个库包,可以被嵌入应用程序,Tcl的库包含了一个分析器、用于执行内建命令的例程和可以使你扩充(定义新的过程)的库函数。应用程序可以产生Tcl命令并执行,命令可以由用户产生,也可以从用户接口的一个输入中读取(按钮或菜单等)。但Tcl库收到命令后将它分解并执行内建的命令,经常会产生递归的调用。 下面简单介绍以下tcl的语法规则: 解释器 在Tcl的数据结构中的核心是Tcl_Interp.一个解释器包含了一套命令,一组变量和一些用于描述状态的东西。每一个 Tcl命令是在特定的 Tcl_Interp中运行的,基于Tcl的应用程序可以同时拥有几个Tcl_Interp。 Tcl_Interp是一个轻量级的结构,可以快速的新建和删除。 数据类型 Tcl只支持一种数据结构:字符串(string)。所有的命令,命令的所有的参数,命令的结果,所有的变量都是字符串。请牢记这一点,所有的东西都是字符串。这是它比较有特点的方面字符串有三种形式:命令(command), 表达式(expresion)和表(list)。 Basic Command Syntax 基本语法 Tcl有类似于shell和lisp的语法,当然也有许多的不同。一条Tcl的命令串包含了一条或多条命令用换行符或分号来隔开,而每一条命令包含了一个域(field)的集合,域使用空白分开的,第一个域是一个命令的名字,其它

tcl_tk编程,tcl_tk编程教程

Tcl / Tk 大全 (1) 一. Tcl / Tk简介 (1) 1.1 背景 (1) 1.2 定义 (2) 二. Tcl / Tk基础 (2) 2.1 交互方式 (3) 2.2 非交互方式 (3) 三. TCL总体结构图 (4) 四. 与其它语言的比较 (4) 五. TCL语法 (5) 5.1 t c l 命令结构. (5) 5.2 TCL 的注释 (5) 5.3 数据类型 (5) 5.4 变量 (6) 5.5 字符串的操作 (8) 5.6 引用和置换 (10) 5.7 流的控制 IF 和 SWITCH (12) 5.8文件的输入输出和文件的信息 (14) 5.9 过程 (16) 六.工具箱 (17) 6.1 构件的介绍 (17) 6.2 创建构件 (18) 6.3 构件的选项 (18) 6.4 一个TCL./TK 构件的编程示例 (19) 七. 小结 (20) Tcl / Tk 大全 摘要: Tcl/Tk 是一种简明,高效,可移植性好的编程语言。在信息产业领域具有广泛的应用。本文描述了TCL/TK成长历史,特点,优势及应用范围,阐述了TCL/TK的总体结构图,比较了TCL/TK与当今流行的C++,Java 的性能比较,详细阐述了TCL/TK的语法,并介绍了TK的工具箱. 一. Tcl / Tk简介 1.1 背景 Tcl/Tk 的发明人 John Ousterhout 教授在八十年代初,是伯克利大学的教授。在其教学过程中,他发现在集成电路 CAD 设计中,很多时间是花在编程建立测试环境上。并且,环境一旦发生了变化,就要重新修改代码以适应。这种费力而又低效的方法,迫使Ousterhout 教授力图寻找一种新的编程语言,它即要有好的代码可重用性,又要简单易学,这样就促成了 Tcl (Tool Command Language) 语言的产生。 Tcl 最初的构想的是希望把编程按照基于组件的方法 (component approach),即与其为单个的应用程序编写成百上千行的程序代码,不如寻找一个种方法将程序分割成一个个小

相关主题
文本预览
相关文档 最新文档