隨筆-1  評論-0  文章-0  trackbacks-0
            2006年4月13日
          關于linux socket編程的lecture
          http://www.aka.org.cn/Lectures/002/Lecture-2.1.8/Lecture-2.1.8/index.htm

          阻塞模式

          socket的缺省方式,也是最常用的方式,即函數阻塞直到調用完畢。

          可能造成阻塞的函數有:recvfrom() 、connect()、accept()、讀寫函數、select()、poll()、gethostbyname()等。

          ????????????????

          #include <stdio.h>
          #include <stdlib.h>
          #include <errno.h>
          #include <string.h>
          #include <sys/types.h>
          #include <netinet/in.h>
          #include <sys/socket.h>
          #include <sys/wait.h>
          #define MYPORT 3490??????????????? ? /* 監聽的端口 */
          #define BACKLOG 10??????????????? ?? /* listen的請求接收隊列長度 *

          void main() {

          int sockfd, new_fd;??????????? /* 監聽端口,數據端口 */
          struct sockaddr_in sa;???????? /* 自身的地址信息 */
          struct sockaddr_in their_addr; /* 連接對方的地址信息 */
          int sin_size;

          if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {??
          ??? perror("socket");
          ??? exit(1);
          }
          sa.sin_family = AF_INET;
          sa.sin_port = htons(MYPORT);???????? /* 網絡字節順序 */
          sa.sin_addr.s_addr = INADDR_ANY;???? /* 自動填本機IP */
          bzero(&(sa.sin_zero), 8);???????????? /* 其余部分置0 */
          if (bind(sockfd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {??
          ??? perror("bind");
          ??? exit(1);
          }
          if (listen(sockfd, BACKLOG) == -1) {??
          ??? perror("listen");
          ??? exit(1);
          }
          /* 主循環 */

          while(1) {
          ??? sin_size = sizeof(struct sockaddr_in);
          ??? new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size));
          ??? if (new_fd == -1) {
          ??? ??? perror("accept");
          ??? ??? continue;
          ??? }
          ??? printf(”Got connection from %s\n", inet_ntoa(their_addr.sin_addr));
          ??? if (fork() == 0) {??? /* 子進程 */?? ??
          ??? ??? if (send(new_fd, "Hello, world!\ n", 14, 0) == -1)?? ??
          ??? ??? ??? perror("send");
          ??? ??? ??? close(new_fd);
          ??? ??? ??? exit(0);
          ??? }
          ??? close(new_fd);??? /*清除所有子進程 */
          ??? while(waitpid(-1,NULL,WNOHANG) > 0);
          ?}
          }


          非阻塞模式

          程序調用可能造成阻塞的函數時:
          如果會發生阻塞,這些函數返回-1并將errno設置為EAGAIN或EWOULDBLOCK,程序可繼續向下運行。可能阻塞
          的函數對應的任務完成,則再次調用該函數時就返回0表示運行結束

          非 阻塞模式可以避免程序死鎖,但是需要程序不斷檢查各個可能阻塞的函數的狀態,當一個應用程序使用了
          非阻塞模式的套接字,它需要使用一個循環來不聽的測試是 否一個文件描述符有數據可讀(稱做polling)。
          應用程序不停的polling內核來檢查是否I/O操作已經就緒。這將是一個極浪費CPU資源的操 作,因此不能實際
          應用。一般非阻塞模式是與同步I/O模式共同使用的。


          ?

          獲得或改變socket的I/O屬性:

          int ioctl(int sockfd,long cmd,unsigned long* argp);

          cmd屬性類型,argp屬性的參數。
          常用的有:
          FIONREAD,返回socket緩沖區中未讀數據的字節數
          FIONBIO,argp為零時為阻塞模式,非零時為非阻塞模式
          SIOCATMARK ,判斷是否有未讀的帶外數據(僅用于TCP協議),返回true或false

          int fcntl(int fd, int cmd, long arg);

          F_SETFL,arp為O_NONBLOCK時進入非阻塞模式,為0時進入阻塞模式。
          F_GETFL,獲得屬性。


          I/O多路復用(同步I/O模式)

          ???? 使用select()、poll()等函數實現對多個socket的同步I/O操作。它能同時等待多個
          socket描述符,而這些socket描述符其中的任意一個進入讀就緒/寫就緒/出錯狀態,select()
          函數就可以返回。

          ??? ??

          ??????

          socket輪詢選擇:

          int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

          應用于多路同步I/O模式


          FD_ZERO(*set) 清空socket集合

          FD_SET(s, *set) 將s加入socket集合

          FD_CLR(s, *set) 從socket集合去掉s

          FD_ISSET(s, *set) 判斷s是否在socket集合

          ???? 常數FD_SETSIZE:集合元素的最多個數

          等待選擇機制:

          int poll(struct pollfd *ufds, unsigned int nfds, int timeout);
          是select機制的一個變種,應用于多路同步I/O模式
          ufds是pollfd結構的數組,數組元素個數為nfds。

          struct pollfd {
          int fd; /* file descriptor */
          short events; /* requested events */
          short revents; /* returned events */
          };
          程序段節選int listenfd, connfd, maxfd=0;
          int nready;
          fd_set rset, allset;
          struct sockaddr_in cliaddr, servaddr;
          int clilen;
          listenfd = socket(AF_INET, SOCK_STREAM, 0);
          if (listenfd > maxfd) maxfd = listenfd;
          memset(&servaddr, 0, sizeof(servaddr));
          servaddr.sin_family = AF_INET;
          servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
          servaddr.sin_port = htons(4321);
          bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
          FD_ZERO(&allset);
          FD_SET(listenfd, &allset);
          listen(listenfd, 10);
          /* main loop */
          while (1) {
          rset = allset;
          nready = select(maxfd+1, &rset, NULL, NULL, NULL);
          if (FD_ISSET(listenfd, &rset)) {
          /* 有新的客戶端連接請求
          clilen = sizeof(cliaddr);
          connfd = accept(listenfd, (struct sockaddr*)&cliaddr,&clilen);
          if (client_num == FD_SETSIZE) {
          fprintf(stderr, "too many clients\n");
          exit(-1);
          }
          FD_SET(connfd, &allset);
          if (connfd > maxfd) maxfd = connfd;
          if (--nready <= 0) continue;
          }
          //以下依次判斷FD_ISSET(某個socket, &rset) 并做相應處理
          }

          信號驅動I/O

          ? ?? ?????????????

          異步I/O



          posted @ 2006-04-13 10:29 steven's home 閱讀(919) | 評論 (0)編輯 收藏
          僅列出標題  
          主站蜘蛛池模板: 东乡| 河池市| 合作市| 卫辉市| 韶山市| 玛曲县| 象山县| 玛纳斯县| 天镇县| 长岛县| 中江县| 赞皇县| 信阳市| 徐州市| 剑川县| 承德市| 北安市| 潢川县| 怀安县| 西安市| 长子县| 文水县| 芜湖市| 吴堡县| 广灵县| 韩城市| 芒康县| 大渡口区| 金沙县| 鹰潭市| 博客| 青浦区| 渭南市| 岱山县| 溧水县| 仁寿县| 双城市| 宝清县| 肇源县| 嵊泗县| 五大连池市|