470 likes | 708 Views
網路程式設計 - Socket 程式設計. 蔡進義 cyt@pmlab.iecs.fcu.edu.tw. 大綱. TCP/IP 協定複習 什麼是 Socket Socket API 的使用 Socket 相関資料的結構 常用 Socket API. TCP / IP 協定 複習. FTP , SMTP , Telnet , DNS , SNMP. What is TCP / IP Transmission Control Protocol / Internet Protocol. TCP , UDP. 應用層. Application.
E N D
網路程式設計-Socket程式設計 蔡進義 cyt@pmlab.iecs.fcu.edu.tw
大綱 • TCP/IP協定複習 • 什麼是Socket • Socket API的使用 • Socket相関資料的結構 • 常用Socket API
TCP / IP協定複習 FTP , SMTP , Telnet , DNS , SNMP • What is TCP / IP • Transmission Control Protocol / Internet Protocol TCP , UDP 應用層 Application IP , ARP 傳輸層 Transport Ethernet , FDDI , Token Ring 網路層 Network 網路存取層 Network Access
Port 0 Port 1 Port 2 Port 3 … Port 65535 Port(埠) • 每一台主機有65536個ports • port 0 ~ port 65535 • 一些保留的ports • 20, 21: FTP • 23: Telnet • 80: HTTP • 未保留 • 1024 ~ 5000 Port 80 Port 3333
大綱 • TCP/IP協定複習 • 什麼是Socket • Socket API的使用 • Socket相関資料的結構 • 常用Socket API
什麼是Socket? LINK • Socket首次出現在Berkeley UNIX中,作為網路設計TCP/IP的橋樑 • Socket是一個簡單的應用程式介面(Application Programming Interface, API) • Socket使發展網路程式變得比較簡單。目前,Socket已成為最通用的網路設計介面了。 • Berkeley Socket Interface是一組interface function,介於網路應用程式和作業系統及網路硬體之間,用以提供標準的函數,應用程式可透過呼叫Socket interface以發展TCP/IP的網路應用程式。 • BSD ( Berkeley Software Distribution ) Socket • WinSock
應用程式與Socket關係 應用程式1 應用程式2 應用程式3 應用程式4 網路程式介面API (BSD Socket或Win Sock) TCP/IP 作業系統 網路卡
Socket概念 • Socket的概念和檔案代碼觀念相似,一個Socket就是一個通訊點,以一個整數來表示之。 • Socket並不是TCP或UDP的port number • Socket只是一個代碼代表網路協定中的一組資料 • TCP連線中雙方的IP位址 • 目前連線的狀態
Socket Descriptor Socket(整數)
主機1 主機2 80 21 3333 23 TCP或UDP AP1 AP2 AP3 AP3
大綱 • TCP/IP協定複習 • 什麼是Socket? • Socket API的使用 • Socket相關的資料結構 • 主要的Socket API
socket() socket() bind() connect() listen() accept() write() read() read() write() Socket(連結導向), TCP 建立連線 Client Server
使用write()及read()來傳送與接收資料 read() write() read() write()
Socket(非連結導向), UDP socket() socket() bind() bind() sendto() recvfrom() Client Server sendto() recvfrom()
Client/Server模型 • Client端: • Client開啟一個socket並且使用一個port • Client使用connect以建立連結 • TCP要經過三向交握 • Client使用read/write system call對開啟的socket做讀寫的動作 • 關閉socket以結束連結
socket() • open socket由作業系統如同檔案一般取得一Socket Descriptor,讓Client 端以後可使用這一代號進行網路I/O讀寫。 • bind 是指定 Client 端使用local (也就是本機) 的哪一IP及 Port 進行通訊。若無指定,則連線時由系統幫 Client 程式自動挑選合適的 IP 與 Port。因此對 Client 端而言是 Optional。 • connect 是起始 TCP 的連線,配合 Server 端的 accept System Call完成三向交握,因此於 connect 此 System Call 必需傳給予對方 Server 端的 IP 與 Port 的資訊。 • read/write 針對已經完成連線的 Socket Descriptor 進行 I/O 動作,在此傳送 HTTP的Protocol並得到 Server 回傳的 HTML 檔案內容等。 • close 關閉TCP連線,釋放系統資源。 bind() connect() read() write() close()
Client/Server模型 • Server端: • Server開啟一個socket並佔用一個port • 使socket進入被動模式來等待client的連結 • Server及client利用read/write system call進行對開啟的socket做讀寫的動作 • 關閉socket以結束連結
socket() • open socket由作業系統如同檔案一般取得一Socket Descriptor,讓Server端以後可使用這一代號進行接受外來TCP連線。 • bind 是指定 Server端使用local 的哪一IP及 Port 進行通訊。對Server端而言是必需的。 • listen 表示讓此開啟的 Socket 進入被動模式,配合 accept System Call可接受外來之連線。 • Server 端的 accept System Call接受Client 之 connect System Call 完成三向交握,並產生一新的 Descriptor,此 Descriptor即為與Client 進行 I/O 的代號。 • read/write 針對已經accept 產生之Descriptor 進行 I/O 動作,在此傳送 HTTP的Protocol並得到 Server 回傳的 HTML 檔案內容等。 • close 關閉TCP連線,釋放系統資源。 bind() listen() accept() read() write() close()
140.134.26.50 Most Significant byte first (Network Byte Order) 140 134 26 50 Least Significant byte first (大部分Host Byte Order) 50 26 134 140 範例(Client端) 1/2 //建立socket,若成功傳回socket descriptor,若傳回-1表error if((sockfd=socket(AF_INET, SOCK_STREAM, 0)) == -1) { printf("Socket Error:%s\a\n", strerror(errno)); printf("Socket Error:%s\a\n", strerror(errno)); exit(1); } //填入family, address, port,另外,其他地方要填入0(使用bzero() function) bzero((char*) &server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(portnumber); server_addr.sin_addr = *((struct in_addr *) host->h_addr); //和Server建立連線 if(connect(sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr)) == -1) { printf("Connect Error:%s\a\n", strerror(errno)); exit(1); }
範例(Client端) 2/2 //送資料(hello字串)給Server if(write(sockfd, hello, strlen(hello)) == -1) { printf("Write Error:%s\n", strerror(errno)); exit(1); } //從Server收資料 if((nbytes=read(sockfd, buffer, 1024)) == -1) { printf("Read Error:%s\n", strerror(errno)); exit(1); } buffer[nbytes] = '\0'; printf("I am Client. I have received from Server:%s\n", buffer); close(sockfd); exit(0);
範例(Server端) 1/3 //建立socket,若成功傳回socket descriptor,若傳回-1表error if((sockfd=socket(AF_INET,SOCK_STREAM,0)) == -1) { printf("Socket error:%s\n\a", strerror(errno)); exit(1); } //填入family, address, port,另外,其他地方要填入0(使用bzero() function) bzero((char*)&server_addr,sizeof(struct sockaddr_in)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(portnumber); //port number,以htons(16 bytes)轉成network byte order server_addr.sin_addr.s_addr = htonl(INADDR_ANY); //htonl is for 32-bytes, binary presentation //連接通訊埠 if(bind(sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr)) == -1) { printf("Bind error:%s\n\a", strerror(errno)); exit(1); }
範例(Server端) 2/3 //進入被動狀態,等待連線 if(listen(sockfd,5) == -1) { printf("Listen error:%s\n\a", strerror(errno)); exit(1); } while(1) { sin_size = sizeof(struct sockaddr_in); //接受連線,並產生一個新的socket(new_fd),傳回-1表失敗 //其中client的address將放在client_addr中 if((new_fd=accept(sockfd, (struct sockaddr *)(&client_addr), &sin_size)) == -1) { fprintf(stderr, "Accept error:%s\n\a", strerror(errno)); exit(1); } printf("Server get connection from %s\n", inet_ntoa(client_addr.sin_addr));
範例(Server端) 3/3 //將資料讀進放入buffer陣列中 if((nbytes=read(new_fd, buffer, 1024)) == -1) { printf("Read Error:%s\n", strerror(errno)); exit(1); } buffer[nbytes] = '\0'; printf("I have received:%s\n", buffer); //把hello字串的資料傳回client if(write(new_fd, hello, strlen(hello)) == -1) { printf("Write Error:%s\n", strerror(errno)); exit(1); } close(new_fd); } close(sockfd); exit(0);
大綱 • TCP/IP協定複習 • 什麼是Socket? • Socket API的使用 • Socket相關的資料結構 • 主要的Socket API
Socket相關資料結構 • struct sockaddr • struct sockaddr_in • struct in_addr • struct hostent • struct servent • struct protoent
sockaddr <sys/socket.h> //一般化的位址 struct sockaddr { u_short sa_family; /* type of address, AF_INET, AF_INET (Internet protocol address family) */ char sa_data[14]; /* value of address, specifies the address value */ };
sockaddr_in <netinet/in.h> //IPv4 Socket Address struct sockaddr_in { u_short sin_family; //specifies protocol to use, PF_INET for either of TCP or UDP u_port sin_port; //16 bits, network byte order struct in_addr sin_addr; //32 bits, network byte order char sin_zero[8]; //unused };
一般位址 IPv4 Socket Address
in_addr //Internet address structure struct in_addr { long s_addr; //32-bit(整數) IPv4 address, network byte ordered };
hostent struct hostent { char *h_name; char **h_aliases; int h_addrtype; int h_length; char **h_addr_list; //hptr->h_addr = gethostbyname(“140.134.26.21”); }; #define h_addr h_addr_list[0] h_addr_list h_addr_list[0] h_addr_list[1] … … …
servent struct servent { char *s_name; char **s_aliases; int s_port; char *s_proto; };
protoent struct protoent { char *p_name; char **p_aliases; int p_proto; };
大綱 • TCP/IP協定複習 • 什麼是Socket? • Socket API的使用 • Socket相關的資料結構 • 主要的Socket API
Server 主要的Socket API • socket • 建立socket • bind • 設定socket所使用的local IP及通訊埠 • listen • 設定socket等待client的連結請求 • accept • 接受來自client的連結請求,並建立socket連結 • recv/read • (TCP)接收來自client所傳的資料 • recvfrom • (UDP)接收來自client所傳的資料 • send/write • (TCP)傳送資料到client • sendto • (UDP)傳送資料到client
Client 主要的Socket API • socket • 建立socket • connect • 建立與server端socket連線 • recv/read • (TCP)接收來自server所傳的資料 • recvfrom • (UDP)接收來自server所傳的資料 • send/write • (TCP)傳送資料到server • sendto • (UDP)傳送資料到server
int socket(int family, int type, int protocol); 參數: family: Selects the protocol family to be used; defined in <sys/socket.h>; use PF_INET for TCP or UDP.其他還有PF_UNIX AF_INET IPv4 AF_INET6 IPv6 AF_LOCAL Unix domain protocols ~ IPC AF_ROUTE Routing sockets ~ appls and kernel AF_KEY Key socket AF_UNIX AF_IMPLINK type: Semantics of desired communication protocol; defined in <sys/socket.h>; SOCK_STREAM for TCP; SOCK_DGRAM for UDP; others are possible. SOCK_STREAM stream socket SOCK_DGRAM datagram socket SOCK_RAW raw socket SOCK_PACKET datalink (Linux) protocol: Normally only one per type; defined in /etc/protocols; 6 for TCP, 17 for UDP; Can use 0 (zero) and the socket call will figure out the right protocol to use for the specified type field. 傳回值: Return: return a integer identifier called a handle. (nonnegative descriptor if OK, negative number on error) 範例: Example: To create a TCP socket: int sock; sock = socket(PF_INET, SOCK_STREAM, 0);
int connect(int s, struct sockaddr *name, int namelen); 參數: s: file descriptor of socket; returned by call to socket. name: address of the socket data structure; must fill-in this structure before calling connect. namelen: length of name data structure; sizeof(name). 範例: Example: if(connect(fd, (struct sockaddr*) &srv, sizeof(srv)) < 0) { perror(”connect"); exit(1); }
int bind(int socket, const struct sockaddr *address, int addrlen); 功能: Server端的TCP或UDP會使用到 連結socket到特定的address (IP address & TCP/UDP port) 參數: socket: Descriptor identifying an unbound socket. (returned by the socket function.) address: A pointer to a protocol-specific address addrlen: Length of the value in the name parameter, in bytes. 範例: Example: if(bind(fd, (struct sockaddr*) &srv, sizeof(srv)) < 0) { perror("bind"); exit(1); }
int listen(int s, int backlog); if(listen(fd, 5) < 0) { perror(“listen”); exit(1); }
int accept(int s, struct sockaddr *addr, socklen_t *addrlen); 參數: s: the socket the Server is listening to. addr will be the address (IP + port) of the client that sent the connection request. 傳回值: Return: (new) socket for communicating with this client. 範例: Example: newfd = accept(fd, (struct sockaddr*) &cli, &cli_len); if(newfd < 0) { perror("accept"); exit(1); }
int send (int socket, char *message, int msg_len, intflags) (TCP) • int write(int socket, void *msg, int len); (TCP) • int recv (int socket, char *buffer, int buf_len, int flags) (TCP)
int read(int socket, void *msg, int len); (TCP) 範例: Example: int fd; /* socket descriptor */ char buf[512]; /* used by read() */ int nbytes; /* used by read() */ if((nbytes = read(newfd, buf, sizeof(buf))) < 0) { perror(“read”); exit(1); }
int sendto (int socket, void *msg, int len, int flags, struct sockaddr * to, int tolen ); (UDP) 參數: socket: Descriptor identifying a bound socket. msg: Buffer containing the data to be transmitted. len: Length of the data in buf, in bytes. flags: Indicator specifying the way in which the call is made. (usually set to 0) to: Optional pointer to a sockaddr structure that contains the address of the target socket. tolen: Size of the address in to, in bytes. 範例: Example: int fd; /* socket descriptor */ struct sockaddr_in srv; /* used by sendto() */ srv.sin_family = AF_INET; srv.sin_port = htons(80); srv.sin_addr.s_addr = inet_addr(“128.2.35.50”); nbytes = sendto(fd, buf, sizeof(buf), 0 , (struct sockaddr*) &srv, sizeof(srv)); if(nbytes < 0) { perror(“sendto”); exit(1); }
int recvfrom(int socket, void *msg, int len, int flags, struct sockaddr *from, int *fromlen); (UDP) 範例: Example: int fd; /* socket descriptor */ struct sockaddr_in srv; /* used by bind() */ struct sockaddr_in cli; /* used by recvfrom() */ char buf[512]; /* used by recvfrom() */ int cli_len = sizeof(cli); /* used by recvfrom() */ int nbytes; /* used by recvfrom() */ nbytes = recvfrom(fd, buf, sizeof(buf), 0 /* flags */, (struct sockaddr*) &cli, &cli_len); if(nbytes < 0) { perror(“recvfrom”); }
unsigned long int htonl(unsigned long int hostlong); • Host-to-network byte order for a long word (4 bytes) • unsigned short int htons(unsigned short int hostshort); • Host-to-network byte order for a short word (2 bytes) • unsigned long int ntohl(unsigned long int netlong); • Network-to-host byte order for a long word • unsigned short int ntohs(unsigned short int netshort); • Network-to-host byte order for a short word
struct hostent *gethostbyname (const char *hostname); 定義在<netdb.h>中 struct hostent { char *h_name; /* official (canonical) name of host */ char **h_aliases; /* ptr to array of ptrs to alias names */ int h_addrtype; /* host addr type: AF_INET or AF_INET6 */ int h_length; /* length of address: 4 or 16 */ char **h_addr_list; /* ptr to array of ptrs with IPv4/IPv6 addrs */};#define h_addr h_addr_list[0] /* first address in list */