CSAPP(11)Network Programming
The Client-Server Programming Model
Networks
hub 는 받 은 frame 을 모든 port 에 보 냅 니 다. 그러나 bridge 는 학습 을 통 해 데 이 터 를 목적 포트 에 만 보 냅 니 다 (또는 버 립 니 다).
The Global IP Internet
네트워크 에 서 는 일반적으로 big - endian 으로 데 이 터 를 전송 합 니 다.
DNS
struct{
char *h_name;//official domain name
char **h_aliases;//Null-terminated array of domain names
int h_addrtype;//host address type
int h_length;
char **h_addr_list;
}
#include
// return non-NULL pointer is OK,NULL pointer on error with h_error set
struct hostent *gethostbyname(const char *name);
struct hostent *gethostbyaddr(const char *addr,int len,0);
The Sockets Interface
client
클 라 이언 트 에서 서버 에 연결 할 때 socket 을 사용 하여 만 듭 니 다.
#include
#include
//return nonnegative descriptor if OK,-1 on error
int socket(int domain,int type,int protocol);
//return 0 if ok,-1 on error
int connect(int sockfd,struct sockaddr *serv_addr,int addrlen);
클 라 이언 트 가 서버 로 연결 하 는 여러 단계 가 함께 포 장 될 수 있 습 니 다.
int open_clientfd(char *hostname,int port){
int clientfd;
struct hostent *hp;
struct socketaddr_in serveraddr;
if((clientfd==socket(AF_INET,SOCK_STREAM,0))<0)
return -1;//check errno for cause
if((hp=gethostbyname(hostname))==NULL)
return -2;
bzero((char *)&serveraddr,sizeof(serveraddr));
serveraddr.sin_family=AF_INET;
bcopy((char *)hp->h_addr_list[0],(char *)&serveraddr.sin_addr.s_addr,hp->h_length);
serveraddr.sin_port=htons(port);// big-endian
if(connect(clientfd,(SA *)&serveraddr,sizeof(serveraddr))<0)
return -1;
return clientfd;
}
server
서버 에 서 는 일반적으로 bind 를 사용 하여 포트 를 지정 합 니 다 (addrlen 의 값 은 size of (socketadr in). listen 을 통 해 active socket 을 listening socket 으로 전환 합 니 다 (그 중에서 backlog 는 최대 대기 수 를 말 합 니 다).
#include
int bind(int sockfd,struct sockaddr *my_addr,int addrlen);
int listen(int sockfd,int backlog);
마찬가지 로 서버 감청 포트 도 하나의 함수 로 합 칠 수 있다.
int open_listenfd(int port){
int listenfd,optval=1;
struct sockaddr_in serveraddr;
if((listenfd=socket(AF_INET,SOCK_STREAM,0))<0)
return -1;
if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,(const void *)&optval,sizeof(int))<0)
return -1;
bzero((char *)&serveraddr,sizeof(serveraddr));
serveraddr.sin_family=AF_INET;
serveraddr.sin_addr.s_addr=htonl(INADDR_ANY);//
serveraddr.sin_port=htons((unsigned short)port);
if(bind(listenfd,(SA*)&serveraddr,sizeof(serveraddr))<0)
return -1;
if(listen(listenfd,LISTENQ)<0)
return -1;
return listenfd;
}
accept
위 는 server 에 있어 서 자원 을 분배 한 셈 입 니 다. 진정 으로 client 가 server 를 연결 할 수 있 도록 하려 면 server 가 아래 의 accept 함 수 를 호출 해 야 합 니 다.
#include
//return nonnegative connected descriptor if ok,-1 on error
int accept(int listenfd,struct sockaddr *addr,int *addrlen);
server 가 accept 를 호출 하면 대기 상태 (아래 그림 1) 에 들 어가 클 라 이언 트 가 요청 (아래 그림 2) 을 한 다음 연결 을 만 듭 니 다. server 의 accept 와 client 의 connect 는 모두 돌아 갑 니 다 (아래 그림 3). 각각 descriptor 를 받 아 다음 작업 에 사용 합 니 다.
#include
#include
#include
#include
int Open_listenfd(int port){
int out,optval=1;
struct sockaddr_in serveraddr;
if((out=socket(AF_INET,SOCK_STREAM,0))<0){
return -1;
}
if(setsockopt(out,SOL_SOCKET,SO_REUSEADDR,(const void *)&optval,sizeof(int ))<0){
return -1;
}
bzero((char *)&serveraddr,sizeof(serveraddr));
serveraddr.sin_family=AF_INET;
serveraddr.sin_addr.s_addr=htonl(INADDR_ANY);
serveraddr.sin_port=htons((unsigned short )port);
if(bind(out,(__CONST_SOCKADDR_ARG)&serveraddr,sizeof(serveraddr))<0){
return -1;
}
if(listen(out,LISTENQ)<0)
return -1;
return out;
}
void doit(int fd){
int is_static;
struct stat sbuf;
char buf[MAXLINE],method[MAXLINE],uri[MAXLINE],version[MAXLINE];
char filename[MAXLINE],cgiargs[MAXLINE];
rio_t rio;
rio_readinitb(&rio,fd);
rio_readlineb(&rio,buf,MAXLINE);
sscanf(buf,"%s %s %s",method,uri,version);
if(strcasecmp(method,"GET")){
clienterror(fd,method,"501","Not Implemented","does not implement this method")
}
}
int main(int argc,char **argv) {
int listenfd,connfd,port,clientlen;
struct sockaddr_in clientaddr;
if(2!=argc){
fprintf(stderr,"usage:%s
" ,argv[0]);
return 1;
}
port=atoi(argv[1]);
listenfd=Open_listenfd(port);
while (1){
clientlen=sizeof(clientaddr);
connfd=accept(listenfd,&clientaddr,&clientlen);
doit(connfd);
close(connfd);
}
}
Web Servers
네트워크 서 비 스 를 디 버 깅 할 때 telnet 명령 을 통 해 클 라 이언 트 가 http header 에 Host 가 있 는 것 을 모 의 할 수 있 습 니 다. 이것 은 프 록 시 서버 가 정적 자원 에 대한 캐 시 사용 여 부 를 쉽게 찾기 위해 서 입 니 다. server 는 동적 자원 에 대해 서 는 Common Gateway Interface 를 사용 하여 처리 합 니 다. 이 때 server 는 fork 프로 세 스 를 사용 하여 dup 2 를 사용 하여 재 설정 합 니 다.standard output (cgi 가 출력 하 는 곳 이기 때문에) 에 환경 변 수 를 설정 한 다음 execve 를 호출 하여 * / cgi - bin / adder 를 실행 합 니 다. cgi 는 getenv * 를 통 해 설정 한 환경 변 수 를 가 져 옵 니 다. 이것 이 바로 CGI 표준 입 니 다.
cgi 프로그램 으로서 콘 텐 츠 를 되 돌려 주 는 것 외 에 콘 텐 츠 - type, 콘 텐 츠 - length 등 정 보 를 되 돌려 주어 야 합 니 다. sprintf 를 사용 하여 데 이 터 를 저장 하고 printf 를 사용 하여 stantard out 을 기록 하 며 마지막 으로 fflush 캐 시 를 사용 할 수 있 습 니 다.
The Tiny Web Server
글 에서 예 시 를 제 시 했 지만 진정한 server 에 있어 각종 의외 의 상황 을 처리 해 야 한다 고 지적 했다. 예 를 들 어 클 라 이언 트 가 링크 를 끊 어서 발생 하 는 SIGPIPE 등 이다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
ASA 방화벽 및 라우터 rommon 모니터링 모드 IOS 복구 방법tftp [email protected] via 192.168.1.2 4. IOS를 ASA에 업로드할 때 IOS는 ASA를 불러오지 않고 tftp에서 시작 장치를 안내합니다.이 점은 장치가 시작되면 s...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.