面向连接的网络应用程序分为客户端和服务器端。服务器端的执行流程一般为4步,客户端程序相对简单,一般需要两个步骤。
服务器端执行流程4步如下:
(1)调用socket函数,建立一个套接字,该套接字用于接下来的网络通信。
(2)调用bind函数,将该套接字绑定到一个地址,并制定一个端口号,
(3)调用listen函数,使用该套接字监听连接请求
(4)当请求来到时,调用accept函数复制该套接字处理请求
客户端执行流程2步如下:
(1)调用socket函数,创建一个套接字
(2)调用connect函数使用该套接字与服务器进行连接
服务器端和客户端程序的显著区别在于客户端程序不需要调用bind函数,bind函数的作用是将套接字绑定一个IP地址和端口号,因为这两个元素可以在网络环境中唯一地址表示一个进程。如果套接字没有使用bind函数绑定地址和端口,那么调用listen函数和connect函数的时候内核会自动为套接字绑定。由此可知,如果没有使用bind函数,调用listen函数和connect函数的时候内核会自动为套接字绑定。看起来好像bind函数是多余的,但事实并不是这样。
我们先来看看listen函数和connect是怎么绑定套接字的,connect函数绑定套接字的时候使用的是一个设置好的地址结构(sockaddr_in)作为参数,结构中指定了服务器的地址和需要通信的端口号。但是listen函数没有这个参数,多以listen函数不能够使用设置好的地址结构,只能由系统设置IP地址和端口号。也就是说在服务器端,如果不使用bind函数的话,创建套接字时使用的是当前系统中空闲端口的套接字。
这样的话,服务器端的程序不关心客户端的IP地址,也就说是对应的端口号是内核临时指派的一个端口,是随机的,每次执行服务器程序的时候,使用的都是不同的端口。但是在客户端是需要指定通信的服务器的端口的,如果不使用bind函数,每次的端口是随机的话,那么每次重启服务程序之后都要对客户端的程序进行调整,这样做不仅不合理,而且工作量很大,因此在服务器端bind函数作用非常重要。
下面是一个使用bind函数的服务器端程序,可以作为参考理解。
#include <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <strings.h> #include <ctype.h> #include <sys/socket.h> #include <arpa/inet.h> #define MAX_LINE 100 int main(void) { struct sockaddr_in sin; struct sockaddr_in cin; int l_fd; int c_fd; socklen_t len; char buf[MAX_LINE]; char addr_p[INET_ADDRSTRLEN]; int port = 8000; int n; bzero(&sin, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(port); /*创立套接字,使用TCP协议*/ if((l_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("fail to creat socket"); exit(1); } /*将地址和套节字绑定*/ if(bind(l_fd, (struct sockaddr *) &sin, sizeof(sin)) == -1) { perror("fail to bind"); exit(1); } /*开始监听连接请求*/ if(listen(l_fd, 10) == -1) { perror("fail to listren"); exit(1); } printf("waiting...\n"); while(1) { /*接受连接请求,从此函数中返回后就可以开始通信了*/ if((c_fd = accept(l_fd, (struct sockaddr *) &cin, &len)) == -1) { perror("fail to accept"); exit(1); } /*调用recv函数读取客户端传来的信息,不设置任何特殊的标志*/ n = recv(c_fd, buf, MAX_LINE, 0); if(n = -1) { perror("fail to receive"); exit(1); } else if(n == 0) { printf("the connect has been closed\n "); close(c_fd); continue; } /*将客户端地址转换为字符串*/ inet_ntop(AF_INET, &cin.sin_addr, addr_p, sizeof(addr_p)); printf("client IP is %s, port is %s \n", addr_p, ntohs(cin.sin_port)); printf("connect is : %s\n", buf); n = strlen(buf); sprintf(buf, "%d", n); /*使用send函数将转换后的字符串发送给客户端,不设置任何特殊的标志*/ n = send(c_fd, buf, strlen(buf) + 1, 0); if(n == -1) { perror("fail to send"); exit(1); } if(cloes(c_fd) == -1) { perror("fail to close"); exit(1); } } return 0; }
作者:当年煮酒论英雄
原文链接:https://www.cnblogs.com/6-6-8-8/p/9264988.html
共同学习,写下你的评论
评论加载中...
作者其他优质文章