基本套接字总结(@function)
最近學習了下UNIX下的網絡編程。為了以后查詢方便,總結在這里。
首先套接字的地址定義:
IPv4地址和IPv6地址定義見<netinet/in.h>頭文件定義。為了能夠順利轉換不同的套接字內容,可以查看<sys/socket.h>中定義的通用套接字struct sockaddr;在使用過成中我們可以將struct sockaddr_in 和 sockaddr_in6直接強制轉換成struct sockaddr.
連接過程中我們需要人工指定對應網絡地址。而不同的主機實現中存在不同的數據格式(big-endian OR little-endian),我們需要通過如下轉換函數來保證數據轉換過程中的正確性。
函數列表如下:
#include <netinet/in.h> //from host byte order to network byte order uint16_t htons(uint16_t host16bitvalue)//servaddr.sin_addr.s_addr = htonl(INADDR_ANY); ? uint32_t htonl(uint32_t host32bitvalue)//from network byte order to host byte order uint16_t ntohs(uint16_t host16bitvalue) uint16_t ntohl(uint16_t host16bitvalue)
?地址轉換函數使用:
#include <arpa/inet.h>int inet_pton(int family, const char* strptr, void *addrptr); //成功返回1,格式錯誤返回0,出錯返回-1//示例::Inet_pton(AF_INET, argv[1], &serveraddr.sin_addr);const char* inet_ntop(int family, const void*addrptr, char *strptr, size_t len); //len參數指出緩存區的大小,避免出現溢出
?
基本TCP套接字編程示例程序如下(這里我們read,write等系統IO操作來實現網絡回射服務):
其中涉及到的網絡編程函數包括:socket(),bind(),bzero(),inet_pton(), listen(),connect(),accept()
服務過程中socket()指定所要進行操作的網絡服務是什么, socket(指定協議族, 操作類型, 采用協議)
協議族包括:AF_INET:Pv4; AF_INET6:IPv6; AF_LOCAL:UNIX域協議; AF_ROUTE:路由套接字; AF_KEY:密鑰套接字
操作類型:SOCK_STREAM:字節流; SOCK_DGRAM:數據報; SOCK_SEQPACKET:有序分組; SOCK_RAW:原始套接字
采用協議:IPPROTO_TCP...._UDP...._SCTP
?
需要注意的問題:
Fork子進程后,connfd和listenfd的引用次數變成2,所以需要在子進程和父進程中同時關閉才能保證完全關閉。
多個子進程并發后,會在服務器上產生大量的僵死進程,從而使得大量的服務器資源浪費。為此我們需要捕獲僵死進程的信號SIGCHLD,并做相應的處理。因為UNIX中信號不排隊的設計,采用wait處理完第一個僵死進程的信號后其余的進程信號丟失。從而清理不徹底。為此,這里采用waitpid函數進行處理。
首先,服務器程序:
#include "unp.h" #include <stdio.h> #include <stdlib.h>void str_echo(int sockfd); Sigfunc* signal1(int signo, Sigfunc* func); void sig_child(int signo); int main(int argc, char** argv){int listenfd, connfd;char buff[MAXLINE];pid_t childpid;socklen_t clilen;struct sockaddr_in cliaddr, servaddr;//<sys/socket.h>//int socket(int family, int type, int protocal);listenfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(struct sockaddr_in));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(SERV_PORT);Bind(listenfd, (SA*) &servaddr, sizeof(servaddr));Listen(listenfd, LISTENQ);//working with the signal1(SIGCHLD, sig_child);while(1){clilen = sizeof(cliaddr);connfd = Accept(listenfd, (SA*)&cliaddr, &clilen);if ((childpid = Fork()) == 0){Close(listenfd);str_echo(connfd);exit(0);}Close(connfd);}return 0; }void str_echo(int sockfd){ssize_t n;char buf[MAXLINE]; again:while((n = read(sockfd, buf, MAXLINE) ) > 0)Write(sockfd, buf, n);if (n < 0 && errno == EINTR)goto again;else if (n < 0)err_sys("str_echo: read error");}Sigfunc* signal1(int signo, Sigfunc* func){struct sigaction act, oact;act.sa_handler = func;sigemptyset(&act.sa_mask);act.sa_flags = 0;if ( signo == SIGALRM){ #ifdef SA_INTERRUPT//設定中斷,使該信號處理過程中能夠中斷:act.sa_flags |= SA_INTERRUPT; #endif}else{ #ifdef SA_RESTART//信號處理,設置SA_RESTART標志,使得內核對失敗的//系統調用自動重啟。act.sa_flags |= SA_RESTART; #endif}if (sigaction(signo, &act, &oact) < 0){return SIG_ERR;}return (oact.sa_handler); }void sig_child(int signo){pid_t pid;int stat;/*********************************************** #inlcude <sys/wait.h>這里使用wait函數只能處理第一個返回的僵死進程,因為其UNIX系統信號實現中信號是不進行排隊的。所以我們采用waitpid并且設定最后的選項為WNOHANG.表示內核在沒有進程時不僅行阻塞。***********************************************/// --- pid = wait(&stat);while(( pid = waitpid(-1, &stat, WNOHANG)) > 0)printf("child %d terminated.\n", pid);return; }客戶端程序:
#include "unp.h" #include <stdio.h> #include <stdlib.h>int str_cli1(FILE *fp, int sockfd);int main(int argc, char** argv){int sockfd[5];struct sockaddr_in serveraddr;int i;if (argc < 2)err_quit("Use: clisocket <IPaddress>");for (i = 0; i <5; ++i){sockfd[i] = Socket(AF_INET, SOCK_STREAM,0);bzero(&serveraddr, sizeof(struct sockaddr_in));serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(SERV_PORT);Inet_pton(AF_INET, argv[1], &serveraddr.sin_addr);Connect(sockfd[i], (SA*)&serveraddr, sizeof(serveraddr));}str_cli(stdin, sockfd[0]);exit(0); }int str_cli1(FILE *fp, int sockfd){char sendline[MAXLINE], recvline[MAXLINE];while(Fgets(sendline, MAXLINE, fp) != NULL){Writen(sockfd, sendline, strlen(sendline));if (Readline(sockfd, recvline, MAXLINE) == 0)err_quit("str_cli: server terminated prematurely");Fputs(recvline, stdout);} }?
轉載于:https://www.cnblogs.com/BeDPS/p/3693088.html
總結
以上是生活随笔為你收集整理的基本套接字总结(@function)的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: maven 笔记,概念
- 下一篇: 统计单一进程IOPS
