网络结构模型主要有两种,分布式和集中式。而分布式又分为客户/服务器模型和对等网络模型。
网络模型中的集中式系统的优点是结构简单,安全性好,终端廉价,缺点会对主机造成很大压力,且不能对不同用户进行单独的相应的配置,主要应用实例有自动取款机(ATM)、超市收款机(POS)等。
而分布式系统具有高度的可靠性、均衡负载且能满足不同的需求。分布式中的对等网络模型又可细分为无结构网络、有结构网络、混合式网络和集中式网络。客户服务器模型可以细分为平坦模型和层次模型。平坦模型中所有客户都与一个服务器通信;层次模型中的一个等级的主机是低一级的主机的服务器,同时也作为高一级主机的客户端。
客户/服务器模型是分布式系统中使用最广泛的网络模型,许多商业软件都使用客户/服务器模型,重要的应用层协议也是基于该模型设计的,如HTTP、FTP、DNS、Telnet等。
以下是一个用Winsock模拟的Echo服务器程序和客户端程序。首先介绍以下Echo。Echo是互联网上的一个标准的协议,它是一个非常有用的调试和测试工具,Echo服务器简单地把它接受到的任何信息发回给客户端,它既可以使用TCP,也可以使用UDP协议,知名端口号是7。下面将基于TCP来实现这个协议。
服务器端程序:
#include<stdio.h> #include<winsock2.h> #pragma comment(lib, "ws2_32") /*winsock 使用的库函数*/ #define ECHO_DEF_PORT 7 /*侦听的默认端口*/ #define ECHO_BUF_SIZE 256 /*缓冲区的大小*/ int main(int argc, char **argv) { WSADATA wsa_data; SOCKET echo_soc = 0, /*侦听socket句柄*/ acpt_soc; struct sockaddr_in serv_addr, /*socket的本地地址*/ clnt_addr; /*socket的远端地址*/ unsigned short port = ECHO_DEF_PORT; int result = 0; int addr_len = sizeof(struct sockaddr_in); char recv_buf[ECHO_BUF_SIZE]; if(argc == 2) { port = atoi(argv[1]); } WSAStartup(MAKEWORD(2,0), &wsa_data); /*初始化winsock资源*/ echo_soc = socket(AF_INET, SOCK_STREAM, 0); /*socket的本地地址*/ serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(port); serv_addr.sin_addr.S_un.S_addr = INADDR_ANY; result = bind(echo_soc, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); if(result == SOCKET_ERROR) { printf("[Echo Server] bind error:%d\n", WSAGetLastError()); closesocket(echo_soc); return -1; } listen(echo_soc, SOMAXCONN); printf("[Echo server] is running……\n"); while(1) { acpt_soc = accept(echo_soc, (struct sockaddr*)&clnt_addr, &addr_len); if(acpt_soc == INVALID_SOCKET) { printf("[Echo Server] accept error:%d\n", WSAGetLastError()); break; } result = recv(acpt_soc, recv_buf, ECHO_BUF_SIZE, 0); if(result > 0) { recv_buf[result] = 0; printf("[Echo Server] receives:\"%s\", from %s\r\n", recv_buf, inet_ntoa(clnt_addr.sin_addr)); result = send(acpt_soc, recv_buf, result, 0); } closesocket(acpt_soc); } closesocket(echo_soc); WSACleanup(); return 0; }客户端程序:
#include<stdio.h> #include<winsock2.h> /*winsock2.h 已经包含windows.h*/ #pragma comment(lib, "ws2_32") /*加载winsock库函数的动态链接库*/ #define ECHO_DEF_PORT 7 /*连接的默认端口*/ #define ECHO_BUF_SIZE 256 /*缓冲区的大小*/ int main(int argc, char **argv) { WSADATA wsa_data; /*接受加载进来的套接字库的版本信息*/ SOCKET echo_soc = 0; /*socket句柄*/ struct sockaddr_in serv_addr; /*服务器地址*/ unsigned short port = ECHO_DEF_PORT; int result = 0, send_len = 0; char *test_data = "Hello world!", recv_buf[ECHO_BUF_SIZE]; if(argc < 2) { printf("input %s server_address [port]\n", argv[0]); return -1; } if(argc >=3) { port = atoi(argv[2]); } WSAStartup(MAKEWORD(2,0), &wsa_data); /*初始化winsock资源*/ send_len = strlen(test_data); /*服务器地址*/ serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(port); /*转为网络字节序*/ serv_addr.sin_addr.S_un.S_addr = inet_addr(argv[1]); /*将用ascii表示的IP地址转换无二进制地址*/ if(serv_addr.sin_addr.S_un.S_addr == INADDR_NONE) { printf("[ECHO] invalid address\n"); return -1; } echo_soc = socket(AF_INET, SOCK_STREAM, 0); /*创建socket*/ result = connect(echo_soc, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); if(result == 0) /*连接成功*/ { result = send(echo_soc, test_data, send_len, 0); result = recv(echo_soc, recv_buf, ECHO_BUF_SIZE, 0); /*返回接受到的字节数*/ } if(result > 0) { recv_buf[result] = 0; /*为字符串添加结束符null*/ printf("[Echo Client] receives:\"%s\"\r\n", recv_buf); } else { printf("[Echo Client] error:%d.\r\n", WSAGetLastError()); } closesocket(echo_soc); WSACleanup(); return 0; }