基本套接字总结(@function)
最近學(xué)習(xí)了下UNIX下的網(wǎng)絡(luò)編程。為了以后查詢方便,總結(jié)在這里。
首先套接字的地址定義:
IPv4地址和IPv6地址定義見<netinet/in.h>頭文件定義。為了能夠順利轉(zhuǎn)換不同的套接字內(nèi)容,可以查看<sys/socket.h>中定義的通用套接字struct sockaddr;在使用過成中我們可以將struct sockaddr_in 和 sockaddr_in6直接強(qiáng)制轉(zhuǎn)換成struct sockaddr.
連接過程中我們需要人工指定對(duì)應(yīng)網(wǎng)絡(luò)地址。而不同的主機(jī)實(shí)現(xiàn)中存在不同的數(shù)據(jù)格式(big-endian OR little-endian),我們需要通過如下轉(zhuǎn)換函數(shù)來保證數(shù)據(jù)轉(zhuǎn)換過程中的正確性。
函數(shù)列表如下:
#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)
?地址轉(zhuǎn)換函數(shù)使用:
#include <arpa/inet.h>int inet_pton(int family, const char* strptr, void *addrptr); //成功返回1,格式錯(cuò)誤返回0,出錯(cuò)返回-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參數(shù)指出緩存區(qū)的大小,避免出現(xiàn)溢出
?
基本TCP套接字編程示例程序如下(這里我們r(jià)ead,write等系統(tǒng)IO操作來實(shí)現(xiàn)網(wǎng)絡(luò)回射服務(wù)):
其中涉及到的網(wǎng)絡(luò)編程函數(shù)包括:socket(),bind(),bzero(),inet_pton(), listen(),connect(),accept()
服務(wù)過程中socket()指定所要進(jìn)行操作的網(wǎng)絡(luò)服務(wù)是什么, socket(指定協(xié)議族, 操作類型, 采用協(xié)議)
協(xié)議族包括:AF_INET:Pv4; AF_INET6:IPv6; AF_LOCAL:UNIX域協(xié)議; AF_ROUTE:路由套接字; AF_KEY:密鑰套接字
操作類型:SOCK_STREAM:字節(jié)流; SOCK_DGRAM:數(shù)據(jù)報(bào); SOCK_SEQPACKET:有序分組; SOCK_RAW:原始套接字
采用協(xié)議:IPPROTO_TCP...._UDP...._SCTP
?
需要注意的問題:
Fork子進(jìn)程后,connfd和listenfd的引用次數(shù)變成2,所以需要在子進(jìn)程和父進(jìn)程中同時(shí)關(guān)閉才能保證完全關(guān)閉。
多個(gè)子進(jìn)程并發(fā)后,會(huì)在服務(wù)器上產(chǎn)生大量的僵死進(jìn)程,從而使得大量的服務(wù)器資源浪費(fèi)。為此我們需要捕獲僵死進(jìn)程的信號(hào)SIGCHLD,并做相應(yīng)的處理。因?yàn)閁NIX中信號(hào)不排隊(duì)的設(shè)計(jì),采用wait處理完第一個(gè)僵死進(jìn)程的信號(hào)后其余的進(jìn)程信號(hào)丟失。從而清理不徹底。為此,這里采用waitpid函數(shù)進(jìn)行處理。
首先,服務(wù)器程序:
#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//設(shè)定中斷,使該信號(hào)處理過程中能夠中斷:act.sa_flags |= SA_INTERRUPT; #endif}else{ #ifdef SA_RESTART//信號(hào)處理,設(shè)置SA_RESTART標(biāo)志,使得內(nèi)核對(duì)失敗的//系統(tǒng)調(diào)用自動(dòng)重啟。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函數(shù)只能處理第一個(gè)返回的僵死進(jìn)程,因?yàn)槠銾NIX系統(tǒng)信號(hào)實(shí)現(xiàn)中信號(hào)是不進(jìn)行排隊(duì)的。所以我們采用waitpid并且設(shè)定最后的選項(xiàng)為WNOHANG.表示內(nèi)核在沒有進(jìn)程時(shí)不僅行阻塞。***********************************************/// --- 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);} }?
轉(zhuǎn)載于:https://www.cnblogs.com/BeDPS/p/3693088.html
總結(jié)
以上是生活随笔為你收集整理的基本套接字总结(@function)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: maven 笔记,概念
- 下一篇: 统计单一进程IOPS