函數流程框圖:
建立: int socket(int domain,int type,int protocol);
domain——>協議域:
AF_INET————IPV4。
AF_INET6————IPV6。
AF_LOCAL————Unix域。
type——>類型:
SOCK_STREAM——流式通訊端,TCP協議支援該通訊端(提供連線導向,可靠的Data Transmission Service,資料按位元組流,按順序收發,保證在傳輸過程中無丟失,無冗餘)。
SPCK_DGRAM———資料通訊端,UDP協議支援該通訊端(提供面向不需連線的服務,資料收發無序,不能保證資料的準確到達)。
SOCK_RAM————原始通訊端,常用於檢測新協議。允許對低於傳輸層的協議或物理網路直接存取。
protocol——>協議:
0————自動根據type匹配協議。
IPPROTO_TCP。
IPPROTO_UDP。
傳回值:
>0時為socket描述符;-1為失敗。 關閉: int close(int fd); int shutdown(int sockfd,int howto);
sockfd——socket通訊端。
howto:
SHUT_RD———值為0;關閉串連的讀。
SHUT_WR———值為1;關閉串連的寫。
SHUT_RDWR——值為2;串連的讀和寫都關閉。 綁定: int bind(int socket,const struct sockaddr* address,socklen_t address_len);
socket—————通訊端描述符。
address—————地址和連接埠號碼。
address_len———address緩衝區的長度。
傳回值——————0為成功;SOCKET_ERROR為失敗。 監聽: int listen(int sockfd,int backlog);
socket—————監聽的socket描述符。
backlog————排隊的最大串連個數。
傳回值—————0為成功;-1為失敗。 串連: int connect(int sockfd,const struct sockaddr* addr,socklen_t,addrlen);
sockfd————用戶端的socket描述符。
addr—————伺服器的socket地址。
addrlen————伺服器的socket地址的長度。
傳回值—————0為成功l-1為失敗。 接受: int accept(int sockfd,struct socketaddr* addr,socklen_t* addrlen);
sockfd————伺服器的socket描述符,或,監聽socket描述符。
addr—————用戶端的socket地址。
addrlen————用戶端的socket地址長度。
傳回值————非-1為串連描述符;-1為失敗。 發送: ssize_t write(int fd,const void* buf,size_t len);
fd————檔案描述符。
buf————寫入的資料。
len————寫入資料長度。
傳回值———>0為實際所寫的位元組數;<0出錯。 ssize_t send(int sockfd,const void* buf,size_t len,int flags);
flags——通常為0。
傳回值及其他——同上。 ssize_t sendto(int sockdf,const void* buf,size_t len,int flags,const struct sockaddr* dest_addr,socklen_t addrlen);
dest_addr———目標socket地址。
addrlen————目標socket地址長度。
傳回值及其他——同上。 接收: ssize_t read(int fd,void* buf,size_t len);
buf————讀取檔案。
傳回值——0為讀到檔案的結束;>0實際所讀到的位元組數;<0出錯。 ssize_t recv(int sockfd,void* buf,size_t len,int flags);
flags——————通常為0。
傳回值及其他——同上。 ssize_t recvfrom(int sockdf,void* buf,size_t len,int flags,const struct sockaddr* src_addr,socklen_t addrlen); src_addr————目標socket地址。 addrlen—————目標socket地址長度。 傳回值及其他——同上。 結構體: struct sockaddr:
struct sockaddr { unsigned short sa_family; char sa_data[14];}; struct sockaddr_in:
struct sockaddr_in{ short sin_family; unsigned short sin_port; struct in_addr sin_addr; unsigned char sin_zero[8];}; struct in_addr:
struct in_addr { in_addr_t s_addr;}; in_addr_t:
typedef unsigned int in_addr_t;
struct sockaddr_in6(IPV6):
struct sockaddr_in6{ //IPv6 為固定的24 位元組長度 uint8_t sin6_len; //地址簇類型,為AF_INET6 sa_family_t sin6_family; //16 位連接埠號碼,網路位元組序 in_port_t sin6_port; //32 位流標籤 uint32_t sin6_flowinfo; //128 位IP 位址 struct in6_addr sin6_addr;} 特殊地址設定: 通配地址(0.0.0.0): 主機上所有IP,多網卡並用。 ipv4:
in_addr.sin_addr.s_addr = htonl(INADDR_ANY);
ipv6:
in6_addr.sin6_addr = in6addr_any;
迴環地址(127.0.0.1): 本地虛擬介面,無網卡可用,也不需要網卡。用於檢查本網協議。 ipv4:
in_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
ipv6:
in6_addr.sin6_addr = in6addr_loopback;
廣播位址: 受限廣播位址——255.255.255.255 子網廣播位址——xxx.xxx.xxx.255 全子網廣播———xxx.xxx.255.255 ipv4:
in_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
ipv6: 無。
代碼: tcp_cliect:
#include <stdio.h>#include <string.h>#include <arpa/inet.h>#include <sys/socket.h>void show_info(int connfd){struct sockaddr_in local_addr;bzero(&local_addr,sizeof(local_addr));socklen_t local_addr_len = sizeof(local_addr);getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len);printf("client local %s:%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));struct sockaddr_in peer_addr;bzero(&peer_addr,sizeof(peer_addr));socklen_t peer_addr_len = sizeof(peer_addr);getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len);printf("clinet peer %s:%d\n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));}int main(int argc,char* argv[]){if(4 != argc){printf("usage:%s <ip> <#port> <message>\n",argv[0]);return 1;}int connfd = socket(AF_INET,SOCK_STREAM,0);if(-1 == connfd){perror("socket err");return 1;}struct sockaddr_in remote_addr;bzero(&remote_addr,sizeof(remote_addr));remote_addr.sin_family = AF_INET;remote_addr.sin_addr.s_addr = inet_addr(argv[1]);remote_addr.sin_port = htons(atoi(argv[2]));if(-1 == connect(connfd,(struct sockaddr*)&remote_addr,sizeof(remote_addr))){perror("connect err");return 1;}show_info(connfd);write(connfd,argv[3],strlen(argv[3])+1);printf("client send:%s\n",argv[3]);char buf[BUFSIZ];bzero(buf,BUFSIZ);if(-1 == read(connfd,buf,BUFSIZ)){perror("read err");return 1;}printf("client recv:%s\n",buf);close(connfd);} tcp_server:
#include <stdio.h>#include <string.h>#include <arpa/inet.h>#include <sys/socket.h>void show_info(int connfd){struct sockaddr_in local_addr;bzero(&local_addr,sizeof(local_addr));socklen_t local_addr_len = sizeof(local_addr);getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len);printf("server local %s:%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));struct sockaddr_in peer_addr;bzero(&peer_addr,sizeof(peer_addr));socklen_t peer_addr_len = sizeof(peer_addr);getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len);printf("server peer %s:%d\n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));}int main(int argc,char* argv[]){if(3 != argc){printf("usage:%s <ip> <#port>\n",argv[0]);return 1;}int listenfd = socket(AF_INET,SOCK_STREAM,0);if(-1 == listenfd){perror("listenfd open err");return 1;}printf("socket create OK\n");int flag = 1;setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));struct sockaddr_in local_addr;bzero(&local_addr,sizeof(local_addr));local_addr.sin_family = AF_INET;local_addr.sin_addr.s_addr = inet_addr(argv[1]); local_addr.sin_port = htons(atoi(argv[2]));if(-1 == bind(listenfd,(struct sockaddr*)&local_addr,sizeof(local_addr))){perror("bind err");return 1;}printf("bind OK\n");if(-1 == listen(listenfd,10)){perror("listen err");return 1;}printf("listen OK\n");struct sockaddr_in remote_addr;bzero(&remote_addr,sizeof(remote_addr));socklen_t remote_addr_len = sizeof(remote_addr);int connfd = accept(listenfd,(struct sockaddr*)&remote_addr,&remote_addr_len);if(-1 == connfd){perror("accept err");return 1;}show_info(connfd);printf("accept %s:%d\n",inet_ntoa(remote_addr.sin_addr),ntohs(remote_addr.sin_port));char buf[BUFSIZ];bzero(buf,BUFSIZ);if(-1 == read(connfd,buf,BUFSIZ-1)){perror("read err");return 1;}printf("server recv:%s\n",buf);if(-1 == write(connfd,buf,strlen(buf)+1)){perror("write err");return 1;}printf("server send:%s\n",buf);close(connfd);close(listenfd);} 結果: