#include<sys/socket.h>
#include<arpa/inet.h> //大小端轉換
#include<netdb.h> //DNS
一、Socket套接字
為了開發網絡應用,系統提供一套API函數接口,用于網絡應用開發,這些接口稱為套接字函數
struct sockaddr_int{sin_family=AF_INET;sin_port=8080;sin_addr.s_addr=127.0.0.1;
}addr;
int sockfd=socket(AF_INET,SOCK_STREAM|SOCK_DRAM,0); //socket創建
//成功返回sockfd,失敗返回-1bind(int sockfd,struct sockaddr* addr/*使用舊的網絡信息結構體,向前兼容*/,socklen_t addrlen);
//成功返回0,失敗返回-1。對socket設置自定義信息,保持信息不變listen(sockfd,backlog/*等待連接隊列大小,默認128*/);//監聽連接過程以及對應的鏈接事件(TCPServer)
//成功返回0,失敗返回-1
htons(); //本機到網絡16位,小端轉大端端口號
htonl(); //小端轉大端p
ntohs();
ntohl();
inet_ntop(); //大端序轉字符串
inet_pton();
inet_addr();
connect(int sockfd,struct sockaddr* destaddr,sockelen_t addrlen); //請求連接函數(發起握手請求)
//成功返回0,失敗返回-1,如果網絡異常可能引發阻塞int clientsock = accept(int serversocket,struct sockaddr* clientaddr,socklen_t* addrlen); //阻塞等待并建立連接函數(完成三次握手),連接成功后立即返回
//成功返回sock,失敗返回-1,如果網絡異常可能引發阻塞send(int sockfd,char* msg,int len,MSG_NOSIGNAL/*寫忽略信號*/); //向目標發送網絡信息recv(int sockfd,char* buffer,int size,MSG_DONTWAIT/*非阻塞讀*/); //讀取接收網絡信息
TCP連接方式:keep-alive長鏈接,close短鏈接
//TcpServer.h
#include<mysock.h>#define SHUTDOWN 1/*支持 tcp連接 及連接反饋的模型*/int main(){//close 循環持續連接int server_sock,client_sock;struct sockaddr_in addrClient;socklen_t addrlen;server_sock=net_initializer();printf("Test tcp server version 1.0\n");char client_ip[16];while(SHUTDOWN){addrlen=sizeof(addrClient);client_sock=ACCEPT(server_sock,(struct sockaddr*)&addrClient,&addrlen);bzero(client_ip,16);inet_ntop(AF_INET,&addrClient.sin_addr.s_addr,client_ip,16);//大端序轉字符串printf("client port %d,client ip %s\n",ntohs(addrClient.sin_port),client_ip);first_response(client_sock,client_ip);business(client_sock);//讀取請求,處理請求,反饋響應close(client_sock);}close(server_sock);printf("server tis done\n");return 0;
}
//TcpClient.h
#include<mysock.h>int main(){//創建套接字int server_sock=SOCKET(AF_INET,SOCK_STREAM,IPPROTO_TCP);//服務器套接字信息struct sockaddr_in addrServer;bzero(&addrServer,sizeof(addrServer));addrServer.sin_family=AF_INET;addrServer.sin_port=htons(8080);addrServer.sin_addr.s_addr=inet_addr("82.157.31.74");CONNECT(server_sock,(struct sockaddr*)&addrServer,sizeof(addrServer));int nRecvNum=0;int nSendNum=0;char recvBuf[1024]="";char sendBuf[1024]="";nRecvNum=RECV(server_sock,recvBuf,sizeof(recvBuf),0);printf("server:%s\n",recvBuf);fgets(sendBuf,sizeof(sendBuf),stdin);nSendNum=SEND(server_sock,sendBuf,sizeof(sendBuf),0);nRecvNum=RECV(server_sock,recvBuf,sizeof(recvBuf),0);printf("server:%s\n",recvBuf);close(server_sock);return 0;
}
??套接字函數的包裹,網絡功能的包裹:在系統函數的基礎上,拓展函數的功能,在函數的基礎上包裹一層功能更豐富的函數
//myscok.h
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<errno.h>
#include<ctype.h>
#include<time.h>int SOCKET(int domain,int type,int protocol);
int BIND(int sockfd,const struct sockaddr* addr,socklen_t addrlen);
int LISTEN(int sockfd,int backlog);
int CONNECT(int sockfd,const struct sockaddr* addr,socklen_t addrlen);
int ACCEPT(int sockfd,struct sockaddr* addr,socklen_t* addrlen);
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);int net_initializer();
void first_response(int sock,char* cip);//業務處理模塊
void business(int client_sock);
//mysock.c
#include<mysock.h>int SOCKET(int domain,int type,int protocol){int sock;if((sock=socket(domain,type,protocol))==-1){perror("socket create failed");return -1;}return sock;
}int BIND(int sockfd,const struct sockaddr* addr,socklen_t addrlen){if((bind(sockfd,addr,addrlen))==-1){perror("bind call failed");return -1;}return 0;
}int LISTEN(int sockfd,int backlog){if((listen(sockfd,backlog))==-1){perror("listen call failed");return -1;}return 0;
}int CONNECT(int sockfd,const struct sockaddr* addr,socklen_t addrlen){if((connect(sockfd,addr,addrlen))==-1){perror("connect call failed");return -1;}return 0;
}int ACCEPT(int sockfd,struct sockaddr* addr,socklen_t* addrlen){int sock;if((sock=accept(sockfd,addr,addrlen))==-1){perror("accept call failed");return -1;}return sock;
}ssize_t RECV(int sockfd,void* buf,size_t len,int flags){ssize_t size;if((size=recv(sockfd,buf,len,flags))==-1){if(errno==EAGAIN){printf("recv nonblock return\n");}else{perror("recv call failed");}return -1;}return size;
}ssize_t SEND(int sockfd,const void* buf,size_t len,int flags){ssize_t size;if((size=send(sockfd,buf,len,flags))==-1){perror("send call failed");return -1;}return size;
}int net_initializer(){//套接字信息struct sockaddr_in addrServer;bzero(&addrServer,sizeof(addrServer));addrServer.sin_family=AF_INET;addrServer.sin_port=htons(8080);addrServer.sin_addr.s_addr=htonl(INADDR_ANY);//創建套接字int server_sock;server_sock=SOCKET(AF_INET,SOCK_STREAM,0);BIND(server_sock,(struct sockaddr*)&addrServer,sizeof(addrServer));LISTEN(server_sock,128);return server_sock;
}void first_response(int sock,char* cip){char response[1024];bzero(response,sizeof(response));sprintf(response,"hi, %s wellcome test TCP server.\n",cip);SEND(sock,response,strlen(response),0);
}void business(int client_sock){//讀取一次客戶端請求,處理后,立刻斷開ssize_t recv_size;char recv_buffer[1024];bzero(recv_buffer,sizeof(recv_buffer));recv_size=RECV(client_sock,recv_buffer,sizeof(recv_buffer),0);if((strcmp(recv_buffer,"time\n")==0) || (strcmp(recv_buffer,"time")==0)){//響應系統時間time_t tp;char tbuf[1024];bzero(tbuf,sizeof(tbuf));ctime_r(&tp,tbuf);SEND(client_sock,tbuf,strlen(tbuf),0);printf("server,response time success.\n");close(client_sock);}else{//數據處理,大小寫轉換 toupper()int cnt=0;while(cnt<recv_size){recv_buffer[cnt]=toupper(recv_buffer[cnt]);cnt++;}SEND(client_sock,recv_buffer,recv_size,0);printf("server,response data sucess.\n");close(client_sock);}
}
二、業務
簡易業務:例子
客戶端向服務端發送time關鍵字,服務器接收后,向客戶端返回系統時間
簡單數據處理,客戶端向服務端發送字符串,服務端完成大小寫轉換,并回復
客戶端向服務端發送手機號碼,服務端向手機發送短信,并附帶4位驗證碼,后續的驗證流程忽略