《APUE》读书笔记-第十六章网络IPC:套接字

通过网络套接字可以使得不同计算机上运行的进程相互通信。

1、创建套接字

#include <sys/socket.h>

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

注意:AF_LOCAL域是AF_UNIX的别名,AF_UNSPEC域可以代表任何域。

2、套接字通信是双向的,禁止套接字上的输入/输出

#include < sys/socket.h>

Int shutdown ( int sockfd, int how);

3、处理字节序和网络字节序之间的轮换:

#include< arpa/inet.h>

Uint32_t htonl (uint32_t hostint32);

Uint16_t htons(uint16_t hostint16);

Uint32_t ntohl (uint32_t netint32);

Uint16_t ntohs (uint16_t netint16);

4、地址格式:

Struct sockaddr{

       Sa_family_t sa_family;

       Char sa_data[];}

在Linux中,该结构定义如下:

Struct sockaddr{

       Sa_family_t sa_family;

       Char sa_data[14];};

而在FreeBSD中,该结构定义如下:

Struct sockaddr{

       Unsigned char sa_len;

       Sa_family_t sa_family;

       Char sa_data[14];};

因特网地址定义在<netinet/in.h>中。在IPV4因特网域(AF_INET)中,套接字地址用如下结构sokaddr_in表示:

Struct in_addr{

       In_addr_t s_addr;}

Struct sockaddr_in{

       Sa_family_t sin_family;

       In_port_t sin_port;

Struct in_addr sin_addr;

};

数据类型in_port_t 定义成uint16_t。数据类型in_addr_t 定义成uint32_t。这些整数类型在<sdint.h>中定义并指定了相应的位数。

与IPV4因特网域(AF_INET)相比较,IPV6因特网域(AF_INET6)套接字地址用如下结构sockaddr_in6表示:

Struct in6_addr{

       Uint8_t s6_addr[16];};

 Struct sockaddr_in6{

       Sa_family_t sin6_family;

       In_port_t sin6_port;

       Uint32_t sin6_flowinfo;

       Struct in6_addr sin6_addr;

       Uint32_t sin6_scope_id;}

 在Linux中,sockaddr_in 定义如下:

Struct sockaddr_in{

       Sa_family_t sin_family;

       In_port_t sin_port;

       Struct in_addr sin_addr;

       Unsigned char sin_zero[8];};

5、打印出能被人理解的地址格式函数

#include <arpa/inet.h>

const char * inet_ntop (int domain, const void * restrict addr, char * restrict str, socklen_t size);

Int inet_pton ( int domain, const char * restrict str, void * restrict addr);

 6、找给定计算机的主机信息

#include<netdb.h>

Struct hostent * gethostent (void);

Void sethostent (int stayopen);

Void endhostent (void);

Struct hostent{

       Char * h_name;

       Char ** h_aliases;

       Int h_addrtype;

       Int h_length;

       Char ** h_addr_list;};

7、从接口获得网络名字和网络号:

#include<netdb.h.

Struct netent * getnetbyaddr (uint32_t net, int type);

Struct netent * getnetbyname (const char * name);

Struct netent * getnetent (void);

Void setnetent (int stayopen);

Void endnetent (void);

 Struct netent{

       Char * n_name;

       Char ** n_aliases;

       Int n_addrtype;

       Uint32_t n_net;};

8、将协议名字和协议号采用以下函数映射

#include <netdb.h>

Struct protoent * getprotobyname (const char * name);

Struct protoent * getprotobynumber (int proto);

Struct protoent * getprotoent (void);

Void setprotoent (int stayopen);

Void endprotoent (void);

Struct protoent{

       Char * p_name;

       Char ** p_aliases;

       Int p_proto;};

9、从一个服务名映射到一个端口号,服务名

#include<netdb.h>

Struct servent * getservbyname (const char * name, const char * proto);

Struct servent * getservbyport (int port, const char * proto);

Struct servent * getservent( (void);

Void setervent (int stayopen);

Void endservent (void);

Struct servent{

       Char * s_name;

       Char ** s_aliases;

       Int s_port;

       Char * s_proto;};

 10、从一个主机名字和服务名字映射到一个地址

#include <sys/socket.h>

#include <netdb.h>

Int getaddrinfo (const char * restrict host, const char * restrict service, const struct addrinfo * restrict hint, struct addrinfo ** restrict res);

Void freeaddrinfo (struct addrinfo * ai);

Struct addrinfo{

       Int ai_flags;

       int ai_family;

       Int ai_socktype;

       Int ai_protocol;

       Socklen_t ai_addrlen;

       Struct sockaddr * ai_addr;

       Char * ai_canonname;

       Struct addrinfo * ai_next;};

11、gai_strerror将返回的错误码转换成错误消息

#include<netdb.h>

Const char * gai_strerror (int error);

 12、将地址转换成主机或者服务名

#include<sys/socket.h>

#include <netdb.h>

Int getnameinfo (const struct sockaddr * restrict addr, socklen_t alen, char * restrict host,socklen_t hostlen, char * restrict service, socklen_t servlen, unsigned int flags);   

写一个程序获取本机的网络信息,程序如下:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 #include <arpa/inet.h>
  5 #include <netdb.h>
  6 #include <sys/socket.h>
  7
  8 void print_family(struct addrinfo *aip)
  9 {
 10     printf("family ");
 11     switch(aip->ai_family)
 12     {
 13     case AF_INET:
 14         printf("inet ");
 15         break;
 16     case AF_INET6:
 17         printf("inet6 ");
 18         break;
 19     case AF_UNIX:
 20         printf("unix ");
 21         break;
 22     case AF_UNSPEC:
 23         printf("unspecified ");
 24         break;
 25     default:
 26         printf("unkown ");
 27     }
 28 }
 29
 30 void print_type(struct addrinfo *aip)
 31 {
 32     printf("type ");
 33     switch(aip->ai_socktype)
 34     {
 35     case SOCK_STREAM:
 36         printf("stream ");
 37         break;
 38     case SOCK_DGRAM:
 39         printf("datagram");
 40         break;
 41     case SOCK_SEQPACKET:
 42         printf("seqpacket ");
 43         break;
 44     case SOCK_RAW:
 45         printf("raw ");
 46         break;
 47     default:
 48         printf("unknown (%d)",aip->ai_socktype);
 49     }
 50 }
 51
 52 void print_protocol(struct addrinfo *aip)
 53 {
 54     printf(" protocol ");
 55     switch(aip->ai_protocol)
 56     {
 57     case 0:
 58         printf("default ");
 59         break;
 60     case IPPROTO_TCP:
 61         printf("TCP ");
 62         break;
 63     case IPPROTO_UDP:
 64         printf("UDP ");
 65         break;
 66     case IPPROTO_RAW:
 67         printf("raw ");
 68         break;
 69     default:
 70         printf("unknown (%d)",aip->ai_protocol);
 71     }
 72 }
 73
 74 void print_flags(struct addrinfo *aip)
 75 {
 76     printf("flags");
 77     if(aip->ai_flags == 0)
 78         printf("0");
 79     else
 80     {
 81         if(aip->ai_flags & AI_PASSIVE)
 82             printf(" passive ");
 83         if(aip->ai_flags & AI_CANONNAME)
 84             printf(" canon ");
 85         if(aip->ai_flags & AI_NUMERICHOST)
 86             printf(" numhost ");
 87     }
 88 }
 89
 90 int main()
 91 {
 92     struct addrinfo *ailist,*aip;
 93     struct addrinfo hint;
 94     struct sockaddr_in *sinp;
 95     const char *addr;
 96     int err;
 97     char abuf[INET_ADDRSTRLEN];
 98     hint.ai_flags = AI_CANONNAME;
 99     hint.ai_family = 0;
100     hint.ai_socktype = 0;
101     hint.ai_protocol = 0;
102     hint.ai_addrlen = 0;
103     hint.ai_canonname = NULL;
104     hint.ai_addr = NULL;
105     hint.ai_next = NULL;
106     if(getaddrinfo("localhost",NULL,&hint,&ailist) != 0)
107     {
108         printf("getaddrinfo error: %s",gai_strerror(err));
109         exit(-1);
110     }
111     for(aip = ailist;aip != NULL;aip = aip->ai_next)
112     {
113         print_flags(aip);
114         print_family(aip);
115         print_type(aip);
116         print_protocol(aip);
117         printf("\n\thost %s",aip->ai_canonname ?aip->ai_canonname : "-");
118         if(aip->ai_family == AF_INET)
119         {
120             sinp = (struct sockaddr_in *)aip->ai_addr;
121             addr = inet_ntop(AF_INET,&sinp->sin_addr,abuf,INET_ADDRSTRLEN);
122             printf(" address %s ",addr?addr:"unknown");
123             printf(" port %d ",ntohs(sinp->sin_port));
124         }
125         printf("\n");
126     }
127     exit(0);
128 }

程序执行结果如下:

13、将套接字与地址绑定

#include <sys/socket.h>

Int bind (int sockfd, const struct sockaddr * addr, socklen_t len );

对于使用的地址有一些限制:

A、 在进程所运行的机器上,指定的地址必须有效,不能指定一个其他机器的地址。

B、 地址必须和创建套接字时的地址族支持的格式相匹配。

C、 端口号必须不小于1024,除非该进程具有相应的特权(即为超级用户)。

D、一般只有套接字端点能够与地址绑定,尽管有些协议允许多重绑定。

14、获取绑定到一个套接字的地址:

#include <sys/socket.h>

Int getsockname ( int sockfd, struct sockaddr * restrict addr, socklen_t * restrict alenp);

注意:在调用getsockname之前,设置alenp为一个指向整数的指针,该整数指定缓冲区sockaddr的大小。返回时,该整数会被设置成返回地址的大小。如果该地址和提供的缓冲区长度不匹配,则将其截断而不报错。如果当前没有绑定到该套接字的地址,其结果没有定义。

15、获得对方地址:

#include <sys/socket.h>

Int getpeername ( int sockfd, struct sockaddr * restrict addr, socklen_t * restrict alenp);

注意:如果套接字已经和对方连接,调用getpeername来找到对方的地址。除了还会返回对方的地址之外,函数getpeername和getsockname一样。

16、建立连接          

#include <sys/socket.h>

Int connect ( int sockfd, const struct sockaddr * addr, socklen_t len);

17、listen函数

#include <sys/socket.h>

Int listen ( int sockfd,int backlog);

18、accept函数

#include <sys/socket.h>

Int accept ( int sockfd, struct sockaddr * restrict addr, socklen_t * restrict len);

19、send、sendto以及sendmsg信息发送函数

#include <sys/socket.h>

Ssize_t send ( int sockfd, const void * buf, size_t nbytes, int flags);

Ssize_t sendto ( int sockfd, const void * buf, size_t nbytes, int flags, const struct sockaddr * destaddr, socklen_t destlen);

Ssize_t sendmsg ( int sockfd, const struct msghdr * msg, int flags);

Struct msghdr{

Void * msg_name;

Socklen_t msg_namelen;

Struct iovec * msg_iov;

Int msg_iovlen;

Void * msg_control;

Socklen_t msg_controllen;

Int msg_flags;

};

19、recv、recvfrom 与recvmsg接收数据函数

#include <sys/socket.h>

Ssize_t recv ( int sockfd, void * buf, size_t nbytes, int flags);

Ssize_t recvfrom ( int sockfd, void * restrict buf, size_t len, int flags, struct sockaddr * restrict addr, socklen_t  * restrict addrlen);

Ssize_t recvmsg ( int sockfd, struct msghdr * msg, int flags);

写个程序练习网络IPC,客户端请求服务器获取当前时间,服务器调用uptime命令将时间发送给客户端。程序如下:

客户端程序:

View Code

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <arpa/inet.h>
 5 #include <netdb.h>
 6 #include <sys/socket.h>
 7 #include <errno.h>
 8 #include <string.h>
 9 #define MAXADDRLEN  256
10 #define BUFLEN      128
11 #define MAXSLEEP    128
12 #define     HOST_NAME_MAX 256
13 //尝试重试的连接
14 int connect_retry(int sockfd,const struct sockaddr *addr,socklen_t alen)
15 {
16     int     nsec;
17     for(nsec =1;nsec <= MAXSLEEP;nsec<<=1)
18     {
19         if(connect(sockfd,addr,alen) == 0)
20             return 0;
21         if(nsec <= MAXSLEEP/2)
22             sleep(nsec);
23     }
24     return -1;
25 }
26 void print_uptime(int sockfd)
27 {
28     int n;
29     char buf[BUFLEN];
30     while((n=recv(sockfd,buf,BUFLEN,0)) > 0)
31         write(STDOUT_FILENO,buf,n);
32     if(n<0)
33     {
34         perror("recv error");
35         exit(-1);
36     }
37 }
38 int main()
39 {
40     struct addrinfo *ailist,*aip;
41     struct addrinfo hint;
42     int sockfd;
43     int err,n;
44     char    *host;
45     #ifdef _SC_HOST_NAME_MAX
46         n = sysconf(_SC_HOST_NAME_MAX);
47         if(n<0)
48     #endif
49         n = HOST_NAME_MAX;
50     host = (char*)malloc(n);
51     if(host == NULL)
52     {
53         perror("malloc() error");
54         exit(-1);
55     }
56     if(gethostname(host,n) < 0)
57     {
58         perror("gethostname() error");
59         exit(-1);
60     }
61     hint.ai_flags = 0;
62     hint.ai_family = 0;
63     hint.ai_socktype = SOCK_STREAM;
64     hint.ai_protocol = 0;
65     hint.ai_addrlen = 0;
66     hint.ai_canonname = NULL;
67     hint.ai_addr = NULL;
68     hint.ai_next = NULL;
69     if(getaddrinfo(host,"ruptime",&hint,&ailist) != 0)
70     {
71         printf("getaddrinfo error: %s",gai_strerror(err));
72         exit(-1);
73     }
74     for(aip = ailist;aip != NULL;aip = aip->ai_next)
75     {
76        if((sockfd = socket(aip->ai_family,SOCK_STREAM,0))<0)
77         err = errno;
78         else
79            printf("socket successfully.\n");
80        if(connect_retry(sockfd,aip->ai_addr,aip->ai_addrlen) < 0)
81         {err = errno;
82         printf("connect error\n");
83         }
84        else
85        {
86            printf("connect server successfully.\n");
87            printf("Receing time from server is: \n");
88            print_uptime(sockfd);
89            exit(0);
90        }
91     }
92     fprintf(stderr,"can't connect to %s: %s\n",host,strerror(err));
93     strerror(err);
94     exit(0);
95 }

服务器程序如下:

View Code

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 #include <arpa/inet.h>
  5 #include <netdb.h>
  6 #include <sys/socket.h>
  7 #include <errno.h>
  8 #include <syslog.h>
  9 #include <string.h>
 10
 11 #define     BUFLEN      128
 12 #define     QLEN        10
 13 #ifndef     Host_NAME_MAX
 14 #define     HOST_NAME_MAX 256
 15 #endif
 16
 17 int initserver(int type,const struct sockaddr *addr,socklen_t alen,int qlen)
 18 {
 19     int fd;
 20     int err = 0;
 21     if((fd = socket(addr->sa_family,type,0)) < 0)
 22     {
 23         return -1;
 24     }
 25     printf("socket is created successfully.\n");
 26     if(bind(fd,addr,alen) < 0)
 27     {
 28         err = errno;
 29         goto errout;
 30     }
 31      printf("bind successfully.\n");
 32     if(type == SOCK_STREAM || type == SOCK_SEQPACKET)
 33     {
 34         if(listen(fd,qlen) < 0)
 35         {
 36             err = errno;
 37             goto errout;
 38         }
 39         printf("listen successfully.\n");
 40     }
 41     return fd;
 42 errout:
 43     close(fd);
 44     errno = err;
 45     return -1;
 46 }
 47
 48 void serve(int sockfd)
 49 {
 50     int     clfd;
 51     FILE    *fp;
 52     char    buf[BUFLEN];
 53     printf("Prepareing for accpet client :\n");
 54     for(;;)
 55     {
 56         clfd = accept(sockfd,NULL,NULL);
 57         if(clfd < 0)
 58         {
 59             syslog(LOG_ERR,"ruptime: accpet error: %s",gai_strerror(errno));
 60             exit(1);
 61         }
 62         printf("received a client request.\n");
 63         //通过管道调用uptime
 64         if((fp =popen("/usr/bin/uptime","r")) == NULL)
 65         {
 66             sprintf(buf,"error: %s\n",strerror(errno));
 67             send(clfd,buf,strlen(buf),0);
 68         }
 69         else
 70         {
 71             while(fgets(buf,BUFLEN,fp) != NULL)
 72                 send(clfd,buf,strlen(buf),0);
 73             pclose(fp);
 74         }
 75         close(clfd);
 76     }
 77 }
 78 int main()
 79 {
 80     struct addrinfo *ailist,*aip;
 81     struct addrinfo hint;
 82     int sockfd;
 83     int err,n;
 84     char    *host;
 85     #ifdef _SC_HOST_NAME_MAX
 86         n = sysconf(_SC_HOST_NAME_MAX);
 87         if(n<0)
 88     #endif
 89         n = HOST_NAME_MAX;
 90     host = (char*)malloc(n);
 91     if(host == NULL)
 92     {
 93         perror("malloc() error");
 94         exit(-1);
 95     }
 96     if(gethostname(host,n) < 0)
 97     {
 98         perror("gethostname() error");
 99         exit(-1);
100     }
101     puts(host);
102     hint.ai_flags = AI_CANONNAME;
103     hint.ai_family = 0;
104     hint.ai_socktype = SOCK_STREAM;
105     hint.ai_protocol = 0;
106     hint.ai_addrlen = 0;
107     hint.ai_canonname = NULL;
108     hint.ai_addr = NULL;
109     hint.ai_next = NULL;
110     if(getaddrinfo(host,"ruptime",&hint,&ailist) != 0)
111     {
112         syslog(LOG_ERR,"getaddrinfo error: %s",gai_strerror(err));
113         exit(-1);
114     }
115     for(aip = ailist;aip != NULL;aip = aip->ai_next)
116        if((sockfd = initserver(SOCK_STREAM,aip->ai_addr,aip->ai_addrlen,QLEN)) >= 0)
117         {
118             serve(sockfd);
119             exit(0);
120         }
121     exit(-1);
122 }

为了获取ruptime的网络信息,需要编辑/etc/services文件,追加ruptime    4000/tcp   。

程序执行结果如下:

客户端获取服务器时间:

服务器端响应客户请求:

20、带外数据:TCP支持带外数据,但是UDP不支持。TCP仅支持一个字节的紧急数据,但是允许紧急数据在普通数据传递机制数据流之外传输。为了产生紧急数据,在三个send函数中任何一个指定MSG_OOB。如果带MSG_OOB标志传输字节超过一个时,最后一个字节被看作紧急数据字节。当接收到紧急数据时,那么改善信号SIGURG。

TCP支持紧急标记的概念:在普通数据流中紧急数据所在的位置。如果采用套接字选项SO_OOBINLINE,那么可以在普通数据中接收紧急数据。为帮助判断是否接收到紧急标记,可以使用函数sockatmark

#include <sys/socket.h>

Int sockatmark ( int sockfd);

当下一个要读的字节在紧急标志所标识的位置时,sockatmark返回1。当带外数据出现在套接字读取队列时,select函数会返回一个文件描述符并且拥有一个异常状态挂起。可以在普通数据流上接受紧急数据,或者在某个recv函数中MSG_OOB标志在其他队列数据之前接收紧急数据。TCP队列仅有一字节的紧急数据,如果在接收当前的紧急数据字节之前又有新的紧急数据到来,那么当前的字节会被丢弃。

21、在基于套接字异步I/O中,当能够从套接字中读取数据,或者套接字写队列中的空间变得可用时,可以安排发送信号SIGIO。通过两个步骤来使用异步I/O:

1) 建立套接字拥有者关系,信号可以被传送到合适的进程。

2) 通知套接字当I/O操作不会阻塞时发信号告知。

可以使用三种方式来完成第一个步骤:

A、 在fcntl使用F_SETOWN命令

B、 在ioctl中作用FIOSETOWN命令

C、 在ioctl中使用SIOCSPGRP命令。

     要完成第二个步骤,有两个选择:

A、 在fcntl中使用F_SETFL命令并且启用文件标志O_ASYNC。

B、 在ioctl中使用FIOASYNC

时间: 2024-12-03 03:23:56

《APUE》读书笔记-第十六章网络IPC:套接字的相关文章

《APUE》读书笔记-第十四章高级I/O

1.非阻塞I/O 对低速设备的I/O操作可能会使进程永久阻塞,这类系统调用主要有如下情况: (1)如果数据并不存在,则读文件可能会使调用者永远阻塞(例如读管道.终端设备和网络设备). (2)如果数据不能立即被接受,则写这些同样的文件也会使调用者永远阻塞: (3)在某些条件发生之前,打开文件会被阻塞(例如以只写方式打开一个FIFO,那么在没有其他进程已用读方式打开该FIFO时): (4)对已经加上强制性锁的文件进行读.写: (5)某些ioctl操作: (6)某些进程间通信函数: 非阻塞I/O调用o

《APUE》读书笔记—第十二章线程控制

本章介绍了一个进程中多个线程之间如何保持数据的似有性及进程的系统调用如何与线程进行交互. 1.线程限制:  Single Unix定义了一线线程操作的限制,和其他的限制一样,可以通过sysconf来查询.和其它的限制使用目的一样,为了应用程序的在不同操作 系统的可移植性. 一些限制:  PTHREAD_DESTRUCTOR_ITERATIONS: 销毁一个线程数据最大的尝试次数,可以通过_SC_THREAD_DESTRUCTOR_ITERATIONS作为sysconf的参数查询.  PTHREA

《APUE》读书笔记-第十五章进程间通信

进程间通信(IPC)是指能在两个进程间进行数据交换的机制.现代OS都对进程有保护机制,因此两个进程不能直接交换数据,必须通过一定机制来完成. IPC的机制的作用: (1)一个软件也能更容易跟第三方软件或内核进行配合的集成,或移植.如管道,在shell 下执行 ps –aux | grep bash. (2)简化软件结构, 可以把一个软件划分多个进程或线程,通过IPC,集成在一起工作.如消息队列. (3)让操作系统各个模块交换数据,包括内核与应用程序机制. (4)提供进程之间或同一进程之间多线程的

《APUE》读书笔记-第十九章伪终端

1.综述 伪终端对于一个应用程序而言,看上去像一个终端,但事实上伪终端并不是一个真正的终端.从内核角度看,伪终端看起来像一个双向管道,而事实上Solaris的伪终端就是用STREAMS构建的.伪终端总是成对地使用的,就好像是个管道的两端.一端的设备称为"主设备"(master),另一端的设备称为"从设备"(slave),每一对伪终端设备,例如/dev/ptys0和/dev/ttys0,就好像是通过一个管道连在一起,其"从设备"一端与普通的终端设备

MYSQL必知必会读书笔记第十和十一章之使用函数处理数据_Mysql

 mysql简介 MySQL是一种开放源代码的关系型数据库管理系统(RDBMS),MySQL数据库系统使用最常用的数据库管理语言--结构化查询语言(SQL)进行数据库管理. 拼接字段 存储在数据库表中的数据一般不是应用程序所需要的格式.我们需要直接从数据库中检索出转换.计算或格式化过的数据:而不是检索出数据,然后再在客户机应用程序或报告程序中重新格式化. 计算字段(字段 = 列,不过数据库列一般称为列,而字段通常用于计算字段中)并不实际存在于数据库表中,计算字段是运行时在select语句内创建的

Android群英传笔记——第十二章:Android5.X 新特性详解,Material Design UI的新体验

Android群英传笔记--第十二章:Android5.X 新特性详解,Material Design UI的新体验 第十一章为什么不写,因为我很早之前就已经写过了,有需要的可以去看 Android高效率编码-第三方SDK详解系列(二)--Bmob后端云开发,实现登录注册,更改资料,修改密码,邮箱验证,上传,下载,推送消息,缩略图加载等功能 这一章很多,但是很有趣,也是这书的最后一章知识点了,我现在还在考虑要不要写这个拼图和2048的案例,在此之前,我们先来玩玩Android5.X的新特性吧!

第十六章——处理锁、阻塞和死锁(3)——使用SQLServer Profiler侦测死锁

原文:第十六章--处理锁.阻塞和死锁(3)--使用SQLServer Profiler侦测死锁 前言: 作为DBA,可能经常会遇到有同事或者客户反映经常发生死锁,影响了系统的使用.此时,你需要尽快侦测和处理这类问题. 死锁是当两个或者以上的事务互相阻塞引起的.在这种情况下两个事务会无限期地等待对方释放资源以便操作.下面是死锁的示意图: 本文将使用SQLServer Profiler来跟踪死锁.   准备工作: 为了侦测死锁,我们需要先模拟死锁.本例将使用两个不同的会话创建两个事务.   步骤:

python 教程 第十六章、 正则表达式

第十六章. 正则表达式 1)    匹配多个表达式 记号  re1|re2 说明  匹配正则表达式re1或re2 举例  foo|bar  匹配  foo, bar 记号  {N} 说明  匹配前面出现的正则表达式N 举例  [0-9]{3}  匹配  2)    匹配单个/多个/范围内字符 记号  . 说明  匹配任何字符(换行符除外) 举例  b.b  匹配  b和b中间有一个任意字符bab, bcb, bbb 举例  .. (匹配任何两个字符)  匹配  xx, ab 记号  [-] 说明

第十六章——处理锁、阻塞和死锁(1)——确定长时间运行的事务

原文:第十六章--处理锁.阻塞和死锁(1)--确定长时间运行的事务 前言: 事务是OLTP系统中的主要部分.它管理数据一致性和数据并发问题,当多个资源同时被读取或者修改相同数据时,SQLServer会通过锁定机制来确保数据库中的数据总是处于一个有效状态.在SQLServer中,锁管理器是负责实现这些锁机制.SQLServer对于不同的资源类型提供不同的锁类型,如数据库.文件.对象.表.区.页和键. 当你使用事务时,依然会遇到由事务引起的问题,这些通常是由于锁.阻塞和死锁引起的. 本系列将讲解这三