面向连接的协议 [2 ]
2010-08-29 16:31
218 查看
面向连接的协议—服务器端
由图我们可以看出,服务器与客户的区别在于:
服务器必须进行套接口绑定。因为如果服务器没有地址,客户就无法进行连接。
S3
的作用在于告诉内核,在某个套接口上监听并接收请求。
服务器需要监听连接。
下面,我们介绍一下有关的函数,
int
listen(int sockfd, int backlog);
s:
用于监听的套接口。Backlog:
监听队列(the
queue of pending connections)
的最大长度。
2.2
之后的版本中,backlog
的值只包括与监听套接口建立了的连接数。
成功:返回0
,否则,返回
-1
,失败原因 在
errno
中。
监听队列
如上图,对listen
函数调用成功后,在Linux
内核中建立了一个监听队列,它的长度由
backlog
决定。
图中正在处理请求1
,
第2
到
第5
的连接请求被挂起,第6
个请求正在插入队列,同时内核还收到了7,8,9
号
连接。更多的连接正在到达的路上。
accept
函数
int
accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
sockfd:
由socket()
创建,已经用bind()
绑定了一个本地地址,正在监听连接的套接口的描述符。
addr:
用于存放通信的另一端(客户)的套接口地址的变量。
addrlen:
既是输入参数又是输出参数。作为输入参数,它指定了addr
的最大长度。作为输出参数,当函数返回后,它代表了地址的实际长度。
如果函数调用成功,它返回一个新的套接口描述符。否则,返回
-1,
错误的原因记录在errno
中。在新的套接口代表服务器端与客户端进行通信。当客户请求处理完毕时,这个由accept
返回的套接口将关闭。而为了能够接收新的用户请求,在此期间,sockfd
指定的,也就监听套接口,一直处于打开状态。
小节:这里提到了两种套接口,一种是监听套接口,数量只有一个,作用是接收用户请求并创建新的套机口(通信套接口)。另一种,accept
返回的通信套接口,它同用户进程连接,并实现数据的读写操作。
下面是一个简单的TCP/IP
服务器程序,用来代替
daytime
服务器。
成功。
扩展:
TCP/IP
的1~1024
端口都被保留起来了,一般自己写的服务器程序使用>=1024
的端口
0:
表示通配端口,系统会自动的为它分配一个没有使用的端口。
INADDR_ANY:
通配IP
地址。
严格意义上讲,服务器的地址包括
IP
地址和端口号两部分。
一个服务器地址不能完全通配。服务器地址完全通配,当且仅当
Ip
地址和端口号都通配。
这样,在指定了特定端口号后,IP
地址部分可以通配(INADDR_ANY),
这使得服务器可以接受客户发往任何一个本地接口的连接请求。当一个主机有多个IP
接口时(如网关),这极为重要。
由图我们可以看出,服务器与客户的区别在于:
服务器必须进行套接口绑定。因为如果服务器没有地址,客户就无法进行连接。
S3
的作用在于告诉内核,在某个套接口上监听并接收请求。
服务器需要监听连接。
下面,我们介绍一下有关的函数,
int
listen(int sockfd, int backlog);
s:
用于监听的套接口。Backlog:
监听队列(the
queue of pending connections)
的最大长度。
2.2
之后的版本中,backlog
的值只包括与监听套接口建立了的连接数。
成功:返回0
,否则,返回
-1
,失败原因 在
errno
中。
监听队列
如上图,对listen
函数调用成功后,在Linux
内核中建立了一个监听队列,它的长度由
backlog
决定。
图中正在处理请求1
,
第2
到
第5
的连接请求被挂起,第6
个请求正在插入队列,同时内核还收到了7,8,9
号
连接。更多的连接正在到达的路上。
accept
函数
int
accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
sockfd:
由socket()
创建,已经用bind()
绑定了一个本地地址,正在监听连接的套接口的描述符。
addr:
用于存放通信的另一端(客户)的套接口地址的变量。
addrlen:
既是输入参数又是输出参数。作为输入参数,它指定了addr
的最大长度。作为输出参数,当函数返回后,它代表了地址的实际长度。
如果函数调用成功,它返回一个新的套接口描述符。否则,返回
-1,
错误的原因记录在errno
中。在新的套接口代表服务器端与客户端进行通信。当客户请求处理完毕时,这个由accept
返回的套接口将关闭。而为了能够接收新的用户请求,在此期间,sockfd
指定的,也就监听套接口,一直处于打开状态。
小节:这里提到了两种套接口,一种是监听套接口,数量只有一个,作用是接收用户请求并创建新的套机口(通信套接口)。另一种,accept
返回的通信套接口,它同用户进程连接,并实现数据的读写操作。
下面是一个简单的TCP/IP
服务器程序,用来代替
daytime
服务器。
//server.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <netinet/in.h> #include <sys/types.h> #include <sys/socket.h> #include <time.h> static void bail (const char* on_what) { fprintf (stderr, "%s error:%s", on_what, strerror(errno)); exit(1); } int main (int argc, char** argv) { int z; char* srvr_addr = NULL; char* srvr_port = NULL; struct sockaddr_in adr_srvr; struct sockaddr_in adr_clnt; int len_inet = sizeof(adr_srvr); int s;//监听socket int c;//客户端socket int n; time_t td;//当前的日期和时间 char dtbuf[128];//日期/时间信息 //参数过滤 if (argc != 3) { printf ("/tFormat: cmd IP_addr port/n"); exit(1); } //生成监听套接口 s = socket (PF_INET, SOCK_STREAM,0); if (s == -1) { bail ("socket()"); } //生成地址结构 memset (&adr_srvr, 0, sizeof(adr_srvr));//很重要 adr_srvr.sin_family = AF_INET; adr_srvr.sin_port = htons (atoi (argv[2]));//注意这里函数要用对 adr_srvr.sin_addr.s_addr = inet_addr (argv[1]); if (adr_srvr.sin_addr.s_addr == INADDR_ANY) { bail ("inet_addr()"); } //绑定绑定监听套接口 z = bind (s, (const struct sockaddr*)&adr_srvr, sizeof(adr_srvr)); if (z == -1) { bail ("bind ()"); } //开始监听 z = listen (s, 10); if (z == -1) { bail ("listen ()"); } //开始服务循环 while (1) { printf ("等待连接/n"); /* 等待连接 */ len_inet = sizeof(adr_clnt); c = accept (s, (struct sockaddr*)&adr_clnt, (socklen_t*)&len_inet); //阻塞在此处直到有连接 if (c == -1) { bail ("accept()"); } //生成时间戳 time (&td); n = (int) strftime (dtbuf, sizeof(dtbuf), "%A %b %d %H:%M:%S %Y/n", localtime (&td)); //printf ("时间结果:%s/n", dtbuf); //将结果返还给用户 z = write (c, dtbuf, n); if (z == -1) bail ("write()"); printf ("一次通信完成/n"); //关闭通信套接字 close (c); } return 0; } $make server $ ./server 192.168.1.230 9099& //&表示在后台运行 $netstat -n -a -p –tcp//查看你的程序是否处在监听状态 tcp 0 0 192.168.1.230:9099 *:* LISTEN 8636/server $telnet 192.168.1.230 9099 一次通信完成 等待连接 Connected to 192.168.1.230. Escape character is '^]'. Sunday Aug 29 15:57:45 2010 Connection closed by foreign host. 修改 daytime.c程序 adr_srvr.sin_port = sp->s_port; 修改为: adr_srvr.sin_port = htons (atoi("9099")); $make daytime $./daytime 192.168.1.230 //我们用9090端口 一次通信完成 Datetime is Sunday Aug 29 16:00:37 2010 等待连接
成功。
扩展:
TCP/IP
的1~1024
端口都被保留起来了,一般自己写的服务器程序使用>=1024
的端口
0:
表示通配端口,系统会自动的为它分配一个没有使用的端口。
INADDR_ANY:
通配IP
地址。
严格意义上讲,服务器的地址包括
IP
地址和端口号两部分。
一个服务器地址不能完全通配。服务器地址完全通配,当且仅当
Ip
地址和端口号都通配。
这样,在指定了特定端口号后,IP
地址部分可以通配(INADDR_ANY),
这使得服务器可以接受客户发往任何一个本地接口的连接请求。当一个主机有多个IP
接口时(如网关),这极为重要。
相关文章推荐
- 学习笔记《实战Linux Socket编程》第六章 面向非连接的协议
- HTTP 协议本身也是无连接的,虽然它使用了面向连接的 TCP 向上提供的服务。
- Linux网络编程——连接和面向连接的协议之间没有区别
- 笔记5 --TCP是面向连接的运输层协议
- 使用 TCP 协议的面向连接的客户-服务器程序设计
- ISO CONP:面向连接网络协议--网络大典
- 基于 TCP (面向连接)和无连接UDP协议的 socket 套接字编程
- 5 面向非连接的协议
- 学习笔记《实战Linux Socket编程》第七章 面向连接的协议──客户端
- Winsock学习----面向连接的协议(一)
- 【Linux网络编程】无连接和面向连接协议的区别
- 面向连接的协议 [1]
- 学习笔记《实战Linux Socket编程》第八章 面向连接的协议──服务端
- tcp协议是面向连接的,而http是无状态的,面向连接和无状态怎么感觉好像优点矛盾呢?
- 【T01】理解面向连接和无连接协议之间的区别
- TCPIP-TCP是一种面向连接(连接导向)的、可靠的、基于字节流的运输层(Transport layer)通信协议
- Linux网络编程——无连接和面向连接协议的区别
- Linux网络编程——无连接和面向连接协议的区别
- Linux Socket学习--面向非连接的协议
- Windows的网络编程-之二-面向连接的协议