1、socket地址api。socket最開始的含義是一個IP地址和端口對。他惟一地表示了使用TCP通訊的一端。(主要討論ipv4)
編程
一、ipv4socket地址:api
struct sockaddr_in { sa_family_t sin_family; /*地址族:AF_INET*/ u_int16 sin_port; /*端口號,要用網絡字節序表示*/ struct in_addr sin_addr; /*ipv4地址結構*/ }; struct in_addr { u_int32_t s_addr; /*ipv4地址,要用網絡字節表示*/ };
二、ip地址轉換函數服務器
/*字符串轉in_addr*/ #include<arpa/inet.h> int inet_aton(const char *strptr,struct in_addr *addrptr); in_addr_t inet_addr(const char *strptr); int inet_pton(int family,const char *strptr,void *addrptr); /*in_addr轉字符串*/ char *inet_ntoa(struct in_addr inaddr); const char *inet_ntop(int family,const void *addrptr,char *strptr,size_t len);
其中inet_pton和inet_ntop不只能夠轉換ipv4地址,並且能夠轉換ipv6的地址。網絡
2、socket基礎API。建立socket、命名socket、監聽、socket、接收鏈接、發起鏈接、讀寫數據、獲取地址信息。dom
#include<sys/types.h> #include<sys/socket.h> /*建立socket*/ int socket(int domain,int type,int protocol); /*domain表示那個協議,對於TCP/IP協議而言是PF_INET/PT_INET6;type服務類型,TCP使用 SOCK_STREAML(流服務)、UDP使用SOCK_DGRAM(數據報);protocol通常狀況都是0 調用成功返回一個socket文件描述符,失敗返回-1並設置errno*/ /*綁定或命名socket*/ int bind(int sockfd,const struct sockaddr* my_addr,socklen_t addrlen); /*將my_addr所指的socket地址分配給未命名的sockfd文件描述符,addrlen參數是socket地址長度 調用成功返回0,失敗返回-1並設置errno。*/ /*監聽socket*/ int listen(int sockfd,int backlog); /*sockfd參數指定被監聽的socket;backlog提示內核監聽隊列的最大長度,典型值是5。 調用成功返回0,失敗返回-1並設置errno。*/ /*接受鏈接*/ int accept(int sockfd,struct sockaddr *addr,socklen_t* addrlen); /*sockfd參數是執行過listen系統調用的監聽socket。addr參數用來獲取接收鏈接的遠端socket地址 ,該socket地址長度由addrlen參數指出。 調用成功返回一個新的鏈接socket,該socket惟一地標識了被接收的這個鏈接,服務器能夠經過讀寫該 socket來與被接受鏈接對應的客戶端通訊。失敗時返回-1並設置errno*/ /*向服務器發送鏈接*/ int connect(int sockfd,const struct sockaddr *serv_addr,socklen_t addrlen); /*sockfd 參數有socket系統調用返回一個socket。serv_addr參數是服務器監聽的socket地址,addlen 參數指定這個地址的長度。 調用成功返回0。一旦成功創建鏈接,sockfd就惟一地標識了這個鏈接,客戶端就能夠經過讀寫sockfd 來與服務器通訊。失敗返回-1並設置errno*/ /*從socket上讀取數據,向socket上寫數據*/ ssize_t recv(int sockfd,void *buf,size_t len,int flags); ssize_t send(int sockfd,const void *buf,size_t len,int flags); /*recv讀取sockfd上的數據,buf和len參數分別指定緩衝區的位置和大小,flags參數一般是0 send往sockfd上寫入數據,buf和len參數分別指定寫緩衝區的位置和大小。*/ /*關閉socket*/ #include<unistd.h> int close(int fd);
3、使用TCP協議的socket編程的流程以下圖socket
根據上面流程編寫client.cide
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #define MAXLINE 4096 int main(int argc, char** argv) { int sockfd, n,rec_len; char recvline[4096], sendline[4096]; char buf[MAXLINE]; struct sockaddr_in servaddr; if( argc != 2){ printf("usage: ./client <ipaddress>\n"); exit(0); } /*建立socket*/ if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ printf("create socket error: %s(errno: %d)\n", strerror(errno),errno); exit(0); } memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(8000); /*轉換socket地址*/ if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){ printf("inet_pton error for %s\n",argv[1]); exit(0); } /*向服務器發起鏈接*/ if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){ printf("connect error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } printf("send msg to server: \n"); fgets(sendline, 4096, stdin); /*往socket上寫數據*/ if( send(sockfd, sendline, strlen(sendline), 0) < 0) { printf("send msg error: %s(errno: %d)\n", strerror(errno), errno); exit(0); } /*從socket上讀數據*/ if((rec_len = recv(sockfd, buf, MAXLINE,0)) == -1) { perror("recv error"); exit(1); } buf[rec_len] = '\0'; printf("Received : %s ",buf); /*關閉socket*/ close(sockfd); exit(0); }
server.c函數
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #define DEFAULT_PORT 8000 #define MAXLINE 4096 int main(int argc, char** argv) { int socket_fd, connect_fd; struct sockaddr_in servaddr; char buff[4096]; int n; /*建立Socket */ if( (socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){ printf("create socket error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } /*初始化*/ memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//我認爲是任意地址 servaddr.sin_port = htons(DEFAULT_PORT);//設置的端口爲DEFAULT_PORT /*將本地地址綁定到所建立的套接字上*/ if( bind(socket_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){ printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } /*開始監聽是否有客戶端鏈接*/ if( listen(socket_fd, 10) == -1){ printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno); exit(0); } printf("======waiting for client's request======\n"); while(1){ /*阻塞直到有客戶端鏈接,接收鏈接*/ if( (connect_fd = accept(socket_fd, (struct sockaddr*)NULL, NULL)) == -1){ printf("accept socket error: %s(errno: %d)",strerror(errno),errno); continue; } /*接受客戶端傳過來的數據*/ n = recv(connect_fd, buff, MAXLINE, 0); /*向客戶端發送迴應數據*/ if(send(connect_fd, "Hello,you are connected!\n", 26,0) == -1) perror("send error"); buff[n] = '\0'; printf("recv msg from client: %s\n", buff); close(connect_fd); } close(socket_fd); }
運行結果:server
一、運行server程序
blog
二、運行client程序
三、server接收成功