计算机网络
问题:从一个服务器向N个节点分发一个文件需要多长时间?
客户端上传速率= U,F/U = 1小时,Us = 10U,dmin >= Us
覆盖网络(overlay network):Graph
应用编程接口 API(Application Programming Interface)
应用编程接口API:就是应用进程的控制权和操作系统的控制权进行转换的一个系统调用接口
客户端要如何说明与哪个服务器应用进程进行通信呢?
struct sockaddr_in
{
u_char sin_len; /*地址长度 */
u_char sin_family; /*地址族(TCP/IP:AF_INET)*/
u_short sin_port; /*端口号 */
struct in_addr sin_addr; /*IP地址 */
char sin_zero[8]; /*未用(置0) */
}
在这里我们以WinSock为例
wVersionRequested = MAKEWORD(2,1);
err = WSAStartup(wVersionRequested, &wsaData);
struct protoent *p;
p=getprotobyname("tcp");
SOCKET sd=socket(PF_INET,SOCK_STREAM,P->P_PROTO);
置服务器端的流套接字处于监听状态
设置连接请求队列大小(queuesize)
返回值:
/* consock.cpp - connectsock */
#include
#include
#include
#include
#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff
#endif /* INADDR_NONE */
void errexit(const char *,...);
/*--------------------------------------------------------------
* connectsock - allocate & connect a socket using TCP or UDP
* -------------------------------------------------------------
*/
SOCKET connectsock(const char *host, const char *service, const char *transport)
{
struct hostent *phe; /* pointer to host information entry */
struct servent *pse; /* pointer to service information entry */
struct protoent *ppe; /* pointer to protocol information entry*/
struct sockaddr_in sin; /* an Internet endpoint address */
int s,type; /* socket descriptor and socket type */
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
/* Map service name to port number */
if(pse = getservbyname(service, transport))
sin.sin_port = pse->s_port;
else if((sin.sin_port = htons((u_short)atoi(service))) == 0)
errexit("can't get \"%s\"service entry\n",service);
/* Map host name to IP address,allowing for dotted decimal */
if(phe = gethostbyname(host))
memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
else if((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE)
errexit("can't get \"%s\"service entry\n",host);
/* Map protocol name to protocol number */
if((ppe = getprotobyname(transport)) == 0)
errexit("can't get \"%s\"service entry\n",transport);
/* Use protocol to choose a socket type */
if(strcmp(transport, "udp") == 0)
type = SOCK_DGRAM;
else
type = SOCK_STREAM;
/* Allocate a socket */
s = socket(PF_INET, type, ppe->p_proto);
if(s == INVALID_SOCKET)
errexit("can't create socket: %d\n",GetLastError());
/* Connect the socket */
if(connect(s, (struct sockaddr *)&sin, sizeof(sin)) == SOCKET_ERROR)
errexit("can't connect to %s.%s: %d\n",host,service,GetLastError());
return s;
}
/* consock.cpp - connectUDP */
#include
SOCKET connectsock(const char *, const char *, const char *);
/*--------------------------------------------------------------
* connectUDP - connect to a specified UDP service
* on a specified host
* -------------------------------------------------------------
*/
SOCKET connectUDP(const char *host, const char *service)
{
return connectsock(host, service, "udp");
}
/* consock.cpp - connectTCP */
#include
SOCKET connectsock(const char *, const char *, const char *);
/*--------------------------------------------------------------
* connectTCP - connect to a specified TCP service
* on a specified host
* -------------------------------------------------------------
*/
SOCKET connectTCP(const char *host, const char *service)
{
return connectsock(host, service, "tcp");
}
/* errexit.cpp - errexit */
#include
#include
#include
#include
/*--------------------------------------------------------------
* errexit - print an error message and exit
* -------------------------------------------------------------
*/
/*VARARGS1*/
void errexit(const char *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
WSACleanup();
exit(1);
}
/* TCPdtc.cpp - main, TCPdaytime */
#include
#include
#include
void TCPdaytime(const char *, const char *);
void errexit(const char *, ...);
SOCKET connectTCP(const char *, const char *);
#define LINELEN 128
#define WSVERS MAKEWORD(2, 0)
/*--------------------------------------------------------------
* main - TCP client for DAYTIME service
* -------------------------------------------------------------
*/
int main(int argc, char *argv[])
{
char *host = "localhost"; /* host to use if none supplied */
char *service = "daytime"; /* default service port */
WSADATA wsadata;
switch(argc){
case 1:
host = "localhost";
break;
case 3:
service = argv[2];
/* FALL THROUGH */
case 2:
host = argv[1];
break;
default:
fprintf(stderr, "usage: TCPdaytime [host [port]]\n");
exit(1);
}
if(WSAStartup(WSVERS, &wsadata) != 0)
errexit("WSAStartup failed\n");
TCPdaytime(host, service);
WSACleanup();
return 0; /* exit */
}
/*--------------------------------------------------------------------
* TCPdaytime - invoke Daytime on specified host and print results
* -------------------------------------------------------------------
*/
void TCPdaytime(const char *host, const char *service)
{
char buf[LINELEN+1]; /* buffer for one line of text */
SOCKET s; /* socket descriptor */
int cc; /* recv character count */
s = connectTCP(host, service);
cc = recv(s, buf, LINELEN, 0);
while( cc != SOCKET_ERROR && cc > 0)
{
buf[cc] = '\0'; /* ensure null-termination */
(void)fputs(buf, stdout);
cc = recv(s, buf, LINELEN, 0);
}
closesocket(s);
}
/* UDPdtc.cpp - main, UDPdaytime */
#include
#include
#include
void UDPdaytime(const char *, const char *);
void errexit(const char *, ...);
SOCKET connectUDP(const char *, const char *);
#define LINELEN 128
#define WSVERS MAKEWORD(2, 0)
#define MSG "what daytime is it?\n"
/*--------------------------------------------------------------
* main - UDP client for DAYTIME service
* -------------------------------------------------------------
*/
int main(int argc, char *argv[])
{
char *host = "localhost"; /* host to use if none supplied */
char *service = "daytime"; /* default service port */
WSADATA wsadata;
switch(argc){
case 1:
host = "localhost";
break;
case 3:
service = argv[2];
/* FALL THROUGH */
case 2:
host = argv[1];
break;
default:
fprintf(stderr, "usage: UDPdaytime [host [port]]\n");
exit(1);
}
if(WSAStartup(WSVERS, &wsadata) != 0)
errexit("WSAStartup failed\n");
UDPdaytime(host, service);
WSACleanup();
return 0; /* exit */
}
/*--------------------------------------------------------------------
* UDPdaytime - invoke Daytime on specified host and print results
* -------------------------------------------------------------------
*/
void UDPdaytime(const char *host, const char *service)
{
char buf[LINELEN+1]; /* buffer for one line of text */
SOCKET s; /* socket descriptor */
int n; /* recv character count */
s = connectUDP(host, service);
(void)send(s, MSG, strlen(MSG), 0);
/* Read the daytime */
n = recv(s, buf, LINELEN, 0);
if(n == SOCKET_ERROR)
errexit("recv failed: recv() error %d\n", GetLastError());
else
{
buf[cc] = '\0'; /* ensure null-termination */
(void)fputs(buf, stdout);
}
closesocket(s);
return 0; /* exit */
}
4种类型基本服务器
数据发送
获取客户端点地址
主线程1:创建套接字,并绑定熟知端口号;
主线程2:反复调用recvfrom()函数,接收下一个客户请求,并创建新线程处理该客户响应;
子线程1:接收一个特定请求;
子线程2:依据应用层协议构造响应报文,并调用sendto()发送;
子线程3:退出(一个子线程处理一个请求后即终止)。
主线程1:创建(主)套接字,并绑定熟知端口号;
主线程2:创建(主)套接字为被动监听模式,准备用于服务器;
主线程3:反复调用accept()函数接收下一个连接请求(通过主套接字),并创建一个新的子线程处理该客户响应;
子线程1:接收一个客户的服务请求(通过新创建的套接字);
子线程2:遵循应用层协议与特定客户进行交互
子线程3:关闭/释放连接并退出(线程终止)。
/* passsock.cpp - passivesock */
#include
#include
#include
void errexit(const char *, ...);
/*--------------------------------------------------------------
* passivesock - allocate & bind a server socket using TCP or UDP
* -------------------------------------------------------------
*/
SOCKET passivesock(const char *service, const char *transport, int qlen)
{
struct servent *pse; /* pointer to service information entry */
struct protoent *ppe; /* pointer to protocol information entry*/
struct sockaddr_in sin; /* an Internet endpoint address */
SOCKET s; /* socket descriptor */
int type; /* socket type(SOCK_STREAM, SOCK_DGRAM)*/
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
/* Map service name to port number */
if(pse = getservbyname(service, transport))
sin.sin_port = (u_short)pse->s_port;
else if((sin.sin_port = htons((u_short)atoi(service))) == 0)
errexit("can't get \"%s\"service entry\n", service);
/* Map protocol name to protocol number */
if((ppe = getprotobyname(transport)) == 0)
errexit("can't get \"%s\"service entry\n",transport);
/* Use protocol to choose a socket type */
if(strcmp(transport, "udp") == 0)
type = SOCK_DGRAM;
else
type = SOCK_STREAM;
/* Allocate a socket */
s = socket(PF_INET, type, ppe->p_proto);
if(s == INVALID_SOCKET)
errexit("can't create socket: %d\n",GetLastError());
/* Bind the socket */
if(bind(s, (struct sockaddr *)&sin, sizeof(sin)) == SOCKET_ERROR)
errexit("can't bind to %s port: %d\n", service, GetLastError());
if(type == SOCK_STREAM && listen(s,qlen) == SOCKET_ERROR)
errexit("can't listen on %s port: %d\n", service, GetLastError());
return s;
}
/* passUDP.cpp - passiveUDP */
#include
SOCKET passivesock(const char *, const char *, int);
/*------------------------------------------------------------------
* passiveUDP - create a passive socket for use in a UDP servier
* -----------------------------------------------------------------
*/
SOCKET passiveUDP(const char *service)
{
return passivesock(service, "udp", 0);
}
/* passTCP.cpp - passiveTCP */
#include
SOCKET passivesock(const char *, const char *, int);
/*------------------------------------------------------------------
* passiveTCP - create a passive socket for use in a TCP server
* -----------------------------------------------------------------
*/
SOCKET passiveTCP(const char *service,int qlen)
{
return passivesock(service, "tcp", qlen);
}
/* UDPdtd.cpp - main, UDPdaytimed */
#include
#include
#include
void errexit(const char *, ...);
SOCKET passiveUDP(const char *);
#define WSVERS MAKEWORD(2, 0)
/*--------------------------------------------------------------
* main - Iterative UDP server for DAYTIME service
* -------------------------------------------------------------
*/
void main(int argc, char *argv[])
{
struct sockaddr_in fsin; /* the form address of a client */
char *service = "daytime"; /* service name or port number */
SOCKET sock; /* socket */
int alen; /* from-address length */
char * pts; /* pointer to time string */
time_t now; /* current time */
WSADATA wsadata;
switch(argc){
case 1:
break;
case 2:
service = argv[1];
break;
default:
errexit("usage: UDPdaytimed [port]\n");
}
if(WSAStartup(WSVERS, &wsadata) != 0)
errexit("WSAStartup failed\n");
sock = passiveUDP(service);
while(1)
{
alen = sizeof(struct sockaddr);
if(recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&fsin, &alen) == SOCKET_ERROR)
errexit("recvfrom: error %d\n",GetLastError());
(void)time(&now);
pts = ctime(&now);
(void)sendto(sock, pts, strlen(pts), 0 , (struct sockaddr *)&fsin, sizeof(fsin));
}
return 1; /* not reached */
}
/* TCPdtd.cpp - main, TCPdaytimed */
#include
#include
#include
#include
void errexit(const char *, ...);
void TCPdaytimed(SOCKET);
SOCKET passiveTCP(const char *, int);
#define QLEN 5
#define WSVERS MAKEWORD(2, 0)
/*--------------------------------------------------------------
* main - Concurrent TCP server for DAYTIME service
* -------------------------------------------------------------
void main(int argc, char *argv[])
{
struct sockaddr_in fsin; /* the form address of a client */
char *service = "daytime"; /* service name or port number */
SOCKET msock,ssock; /* master & slave sockets */
int alen; /* from-address length */
WSADATA wsadata;
switch(argc){
case 1:
break;
case 2:
service = argv[1];
break;
default:
errexit("usage: TCPdaytimed [port]\n");
}
if(WSAStartup(WSVERS, &wsadata) != 0)
errexit("WSAStartup failed\n");
msock = passiveTCP(service, QLEN);
while(1)
{
alen = sizeof(struct sockaddr);
ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
if(ssock == INVALID_SOCKET)
errexit("accept failed: error number %d\n", GetLastError());
if(_beginthread((void(*)(void *))TCPdaytimed, 0, (void *)ssock) < 0){
errexit("_beginthread: %s\n", strerror(errno));
}
}
return 1; /* not reached */
}
/*--------------------------------------------------------------------
* TCPdaytime - do TCP DAYTIME protocol
* -------------------------------------------------------------------
*/
void TCPdaytimed(SOCKET fd)
{
char * pts; /* pointer to time string */
time_t now; /* current time */
(void)time(&now);
pts = ctime(&now);
(void)send(fd, pts, strlen(pts), 0);
(void)closesocket(fd);
}