亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊(cè) 查看新帖 |

Chinaunix

  平臺(tái) 論壇 博客 文庫(kù)
最近訪問(wèn)板塊 發(fā)新帖
樓主: zhoulifa
打印 上一主題 下一主題

Linux網(wǎng)絡(luò)編程一步一步學(xué)-IPv6下網(wǎng)絡(luò)編程步驟 [復(fù)制鏈接]

論壇徽章:
0
31 [報(bào)告]
發(fā)表于 2007-02-04 14:56 |只看該作者

Linux網(wǎng)絡(luò)編程一步一步學(xué)-用C自己編寫(xiě)一個(gè)telnet服務(wù)器

服務(wù)器源代碼如下:

  1. #include <stdarg.h>
  2. #include <errno.h>
  3. #include <stdio.h>
  4. #include <fcntl.h>
  5. #include <unistd.h>
  6. #include <string.h>
  7. #include <time.h>
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #include <dirent.h>
  11. #include <errno.h>
  12. #include <netinet/in.h>
  13. #include <sys/socket.h>
  14. #include <resolv.h>
  15. #include <arpa/inet.h>
  16. #include <stdlib.h>
  17. #include <signal.h>
  18. #include <getopt.h>

  19. #define DEFAULTIP "127.0.0.1"
  20. #define DEFAULTPORT "23"
  21. #define DEFAULTBACK "10"
  22. #define DEFAULTDIR "/tmp"
  23. #define DEFAULTLOG "/tmp/telnet-server.log"

  24. void prterrmsg(char *msg);
  25. #define prterrmsg(msg)        { perror(msg); abort(); }
  26. void wrterrmsg(char *msg);
  27. #define wrterrmsg(msg)        { fputs(msg, logfp); fputs(strerror(errno), logfp);fflush(logfp); abort(); }

  28. void prtinfomsg(char *msg);
  29. #define prtinfomsg(msg)        { fputs(msg, stdout);  }
  30. void wrtinfomsg(char *msg);
  31. #define wrtinfomsg(msg)        {  fputs(msg, logfp); fflush(logfp);}

  32. #define MAXBUF        1024

  33. char buffer[MAXBUF + 1];
  34. char *host = 0;
  35. char *port = 0;
  36. char *back = 0;
  37. char *dirroot = 0;
  38. char *logdir = 0;
  39. unsigned char daemon_y_n = 0;
  40. FILE *logfp;

  41. #define MAXPATH        150

  42. /*------------------------------------------------------
  43. *--- AllocateMemory - 分配空間并把d所指的內(nèi)容復(fù)制
  44. *------------------------------------------------------
  45. */
  46. void AllocateMemory(char **s, int l, char *d)
  47. {
  48.     *s = malloc(l + 1);
  49.     bzero(*s, l + 1);
  50.     memcpy(*s, d, l);
  51. }
  52. /************關(guān)于本文檔*************************************************************
  53. *filename: telnet-server.c
  54. *purpose: 這是在Linux下用C語(yǔ)言寫(xiě)的telnet服務(wù)器,沒(méi)有用戶名和密碼,直接以開(kāi)啟服務(wù)者的身份登錄系統(tǒng)
  55. *wrote by: zhoulifa(zhoulifa@163.com) 周立發(fā)(http://zhoulifa.bokee.com)
  56. Linux愛(ài)好者 Linux知識(shí)傳播者 SOHO族 開(kāi)發(fā)者 最擅長(zhǎng)C語(yǔ)言
  57. *date time:2007-01-27 17:02
  58. *Note: 任何人可以任意復(fù)制代碼并運(yùn)用這些文檔,當(dāng)然包括你的商業(yè)用途
  59. * 但請(qǐng)遵循GPL
  60. *Thanks to: Google.com
  61. *Hope:希望越來(lái)越多的人貢獻(xiàn)自己的力量,為科學(xué)技術(shù)發(fā)展出力
  62. * 科技站在巨人的肩膀上進(jìn)步更快!感謝有開(kāi)源前輩的貢獻(xiàn)!
  63. **********************************************************************************/

  64. /*------------------------------------------------------
  65. *--- getoption - 分析取出程序的參數(shù)
  66. *------------------------------------------------------
  67. */
  68. void getoption(int argc, char **argv)
  69. {
  70.     int c, len;
  71.     char *p = 0;

  72.     opterr = 0;
  73.     while (1) {
  74.         int option_index = 0;
  75.         static struct option long_options[] = {
  76.             {"host", 1, 0, 0},
  77.             {"port", 1, 0, 0},
  78.             {"back", 1, 0, 0},
  79.             {"dir", 1, 0, 0},
  80.             {"log", 1, 0, 0},
  81.             {"daemon", 0, 0, 0},
  82.             {0, 0, 0, 0}
  83.         };
  84.         /* 本程序支持如一些參數(shù):
  85.          * --host IP地址 或者 -H IP地址
  86.          * --port 端口 或者 -P 端口
  87.          * --back 監(jiān)聽(tīng)數(shù)量 或者 -B 監(jiān)聽(tīng)數(shù)量
  88.          * --dir 服務(wù)默認(rèn)目錄 或者 -D 服務(wù)默認(rèn)目錄
  89.          * --log 日志存放路徑 或者 -L 日志存放路徑
  90.          * --daemon 使程序進(jìn)入后臺(tái)運(yùn)行模式
  91.          */
  92.         c = getopt_long(argc, argv, "H:P:B:D:L",
  93.                         long_options, &option_index);
  94.         if (c == -1 || c == '?')
  95.             break;

  96.         if(optarg)        len = strlen(optarg);
  97.         else        len = 0;

  98.         if ((!c && !(strcasecmp(long_options[option_index].name, "host")))
  99.             || c == 'H')
  100.             p = host = malloc(len + 1);
  101.         else if ((!c
  102.                   &&
  103.                   !(strcasecmp(long_options[option_index].name, "port")))
  104.                  || c == 'P')
  105.             p = port = malloc(len + 1);
  106.         else if ((!c
  107.                   &&
  108.                   !(strcasecmp(long_options[option_index].name, "back")))
  109.                  || c == 'B')
  110.             p = back = malloc(len + 1);
  111.         else if ((!c
  112.                   && !(strcasecmp(long_options[option_index].name, "dir")))
  113.                  || c == 'D')
  114.             p = dirroot = malloc(len + 1);
  115.         else if ((!c
  116.                   && !(strcasecmp(long_options[option_index].name, "log")))
  117.                  || c == 'L')
  118.             p = logdir = malloc(len + 1);
  119.         else if ((!c
  120.                   &&
  121.                   !(strcasecmp
  122.                     (long_options[option_index].name, "daemon")))) {
  123.             daemon_y_n = 1;
  124.             continue;
  125.         }
  126.         else
  127.             break;
  128.         bzero(p, len + 1);
  129.         memcpy(p, optarg, len);
  130.     }
  131. }

  132. int main(int argc, char **argv)
  133. {
  134.     struct sockaddr_in addr;
  135.     int sock_fd, addrlen;

  136.     /* 獲得程序工作的參數(shù),如 IP 、端口、監(jiān)聽(tīng)數(shù)、網(wǎng)頁(yè)根目錄、目錄存放位置等 */
  137.     getoption(argc, argv);

  138.     if (!host) {
  139.         addrlen = strlen(DEFAULTIP);
  140.         AllocateMemory(&host, addrlen, DEFAULTIP);
  141.     }
  142.     if (!port) {
  143.         addrlen = strlen(DEFAULTPORT);
  144.         AllocateMemory(&port, addrlen, DEFAULTPORT);
  145.     }
  146.     if (!back) {
  147.         addrlen = strlen(DEFAULTBACK);
  148.         AllocateMemory(&back, addrlen, DEFAULTBACK);
  149.     }
  150.     if (!dirroot) {
  151.         addrlen = strlen(DEFAULTDIR);
  152.         AllocateMemory(&dirroot, addrlen, DEFAULTDIR);
  153.     }
  154.     if (!logdir) {
  155.         addrlen = strlen(DEFAULTLOG);
  156.         AllocateMemory(&logdir, addrlen, DEFAULTLOG);
  157.     }

  158.     printf
  159.         ("host=%s port=%s back=%s dirroot=%s logdir=%s %s是后臺(tái)工作模式(進(jìn)程ID:%d)\n",
  160.          host, port, back, dirroot, logdir, daemon_y_n?"":"不", getpid());

  161.     /* fork() 兩次處于后臺(tái)工作模式下 */
  162.     if (daemon_y_n) {
  163.         if (fork())
  164.             exit(0);
  165.         if (fork())
  166.             exit(0);
  167.         close(0), close(1), close(2);
  168.         logfp = fopen(logdir, "a+");
  169.         if (!logfp)
  170.             exit(0);
  171.     }

  172.     /* 處理子進(jìn)程退出以免產(chǎn)生僵尸進(jìn)程 */
  173.     signal(SIGCHLD, SIG_IGN);

  174.     /* 創(chuàng)建 socket */
  175.     if ((sock_fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
  176.         if (!daemon_y_n) {
  177.             prterrmsg("socket()");
  178.         } else {
  179.             wrterrmsg("socket()");
  180.         }
  181.     }

  182.     /* 設(shè)置端口快速重用 */
  183.     addrlen = 1;
  184.     setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &addrlen,
  185.                sizeof(addrlen));

  186.     addr.sin_family = AF_INET;
  187.     addr.sin_port = htons(atoi(port));
  188.     addr.sin_addr.s_addr = inet_addr(host);
  189.     addrlen = sizeof(struct sockaddr_in);
  190.     /* 綁定地址、端口等信息 */
  191.     if (bind(sock_fd, (struct sockaddr *) &addr, addrlen) < 0) {
  192.         if (!daemon_y_n) {
  193.             prterrmsg("bind()");
  194.         } else {
  195.             wrterrmsg("bind()");
  196.         }
  197.     }

  198.     /* 開(kāi)啟臨聽(tīng) */
  199.     if (listen(sock_fd, atoi(back)) < 0) {
  200.         if (!daemon_y_n) {
  201.             prterrmsg("listen()");
  202.         } else {
  203.             wrterrmsg("listen()");
  204.         }
  205.     }
  206.     while (1) {
  207.         int new_fd;
  208.         addrlen = sizeof(struct sockaddr_in);
  209.         /* 接受新連接請(qǐng)求 */
  210.         new_fd = accept(sock_fd, (struct sockaddr *) &addr, &addrlen);
  211.         if (new_fd < 0) {
  212.             if (!daemon_y_n) {
  213.                 prterrmsg("accept()");
  214.             } else {
  215.                 wrterrmsg("accept()");
  216.             }
  217.             break;
  218.         }
  219.         bzero(buffer, MAXBUF + 1);
  220.         sprintf(buffer, "連接來(lái)自于: %s:%d\n",
  221.                 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
  222.         if (!daemon_y_n) {
  223.             prtinfomsg(buffer);
  224.         } else {
  225.             wrtinfomsg(buffer);
  226.         }
  227.         /* 產(chǎn)生一個(gè)子進(jìn)程去處理請(qǐng)求,當(dāng)前進(jìn)程繼續(xù)等待新的連接到來(lái) */
  228.         if (!fork()) {
  229.             /* 把socket連接作為標(biāo)準(zhǔn)輸入、輸出、出錯(cuò)句柄來(lái)用 */
  230.             dup2(new_fd, 0);
  231.             dup2(new_fd, 1);
  232.             dup2(new_fd, 2);
  233.             /* 切換到指定目錄工作 */
  234.             chdir(dirroot);
  235.             /* 交互式執(zhí)行shell */
  236.             execl("/bin/bash", "-l", "--login", "-i", "-r", "-s", (char *)NULL);
  237.         }
  238.         close(new_fd);
  239.     }
  240.     close(sock_fd);
  241.     return 0;
  242. }
復(fù)制代碼

用下列命令編譯程序:
gcc -Wall telnet-server -o telnetd

啟動(dòng)telnet服務(wù):
./telnetd --daemon #以root用戶身份在23端口(即telnet默認(rèn)端口服務(wù))


./telnetd -P 7838 #以非root用戶身份

然后開(kāi)啟一個(gè)新終端,telnet連接自己的服務(wù)器試試,如:
telnet 127.0.0.1


telnet 127.0.0.1 7838

不需要輸入用戶名和密碼,直接以啟動(dòng)telnet服務(wù)的用戶的身份登錄系統(tǒng)了。
輸入系統(tǒng)命令體驗(yàn)一下吧!

論壇徽章:
0
32 [報(bào)告]
發(fā)表于 2007-02-04 15:04 |只看該作者

Linux網(wǎng)絡(luò)編程一步一步學(xué)-網(wǎng)絡(luò)編程函數(shù)說(shuō)明-來(lái)自“永遠(yuǎn)的UNIX”

www.fanqiang.com(永遠(yuǎn)的UNIX)網(wǎng)站上也有一系統(tǒng)文章,比較詳細(xì)地介紹了網(wǎng)絡(luò)編程的各函數(shù),大家可以去那邊看看,我就不復(fù)制過(guò)來(lái)了。

那邊系列文章的目錄和鏈接如下:
/************關(guān)于本文檔*************************************************************
*filename: Linux網(wǎng)絡(luò)編程一步一步學(xué)-網(wǎng)絡(luò)編程函數(shù)說(shuō)明-來(lái)自“永遠(yuǎn)的UNIX”
*purpose: 詳細(xì)說(shuō)明Linux下網(wǎng)絡(luò)編程各函數(shù)的具體用法,當(dāng)然最好的是各位自己查看在線手冊(cè)man
*tidied by: zhoulifa(zhoulifa@163.com) 周立發(fā)(http://zhoulifa.bokee.com)
Linux愛(ài)好者 Linux知識(shí)傳播者 SOHO族 開(kāi)發(fā)者 最擅長(zhǎng)C語(yǔ)言
*date time:2007-01-27 19:22
*Note: 任何人可以任意復(fù)制代碼并運(yùn)用這些文檔,當(dāng)然包括你的商業(yè)用途
* 但請(qǐng)遵循GPL
*Thanks to: Google.com
*Hope:希望越來(lái)越多的人貢獻(xiàn)自己的力量,為科學(xué)技術(shù)發(fā)展出力
* 科技站在巨人的肩膀上進(jìn)步更快!感謝有開(kāi)源前輩的貢獻(xiàn)!
**********************************************************************************/
Linux網(wǎng)絡(luò)編程--1. Linux網(wǎng)絡(luò)知識(shí)介紹
1.1 客戶端程序和服務(wù)端程序
1.2 常用的命令
1.3 TCP/UDP介紹
Linux網(wǎng)絡(luò)編程--2. 初等網(wǎng)絡(luò)函數(shù)介紹(TCP)
2.1 socket
2.2 bind
2.3 listen
2.4 accept
2.5 connect
2.6 實(shí)例
2.7 總結(jié)
Linux網(wǎng)絡(luò)編程--3. 服務(wù)器和客戶機(jī)的信息函數(shù)
3.1 字節(jié)轉(zhuǎn)換函數(shù)
3.2 IP和域名的轉(zhuǎn)換
3.3 字符串的IP和32位的IP轉(zhuǎn)換
3.4 服務(wù)信息函數(shù)
3.5 一個(gè)例子
Linux網(wǎng)絡(luò)編程--4. 完整的讀寫(xiě)函數(shù)
4.1 寫(xiě)函數(shù)write
4.2 讀函數(shù)read
4.3 數(shù)據(jù)的傳遞
Linux網(wǎng)絡(luò)編程--5. 用戶數(shù)據(jù)報(bào)發(fā)送
5.1 兩個(gè)常用的函數(shù)
5.2 一個(gè)實(shí)例
Linux網(wǎng)絡(luò)編程--6. 高級(jí)套接字函數(shù)
6.1 recv和send
6.2 recvfrom和sendto
6.3 recvmsg和sendmsg
6.4 套接字的關(guān)閉
6.5 shutdown
Linux網(wǎng)絡(luò)編程--7. TCP/IP協(xié)議
7.1 網(wǎng)絡(luò)傳輸分層
7.2 IP協(xié)議
7.3 ICMP協(xié)議
7.4 UDP協(xié)議
7.5 TCP
7.6 TCP連接的建立
Linux網(wǎng)絡(luò)編程--8. 套接字選項(xiàng)
8.1 getsockopt和setsockopt
8.2 ioctl
Linux網(wǎng)絡(luò)編程--9. 服務(wù)器模型
9.1 循環(huán)服務(wù)器:UDP服務(wù)器
9.2 循環(huán)服務(wù)器:TCP服務(wù)器
9.3 并發(fā)服務(wù)器:TCP服務(wù)器
9.4 并發(fā)服務(wù)器:多路復(fù)用I/O
9.5 并發(fā)服務(wù)器:UDP服務(wù)器
9.6 一個(gè)并發(fā)TCP服務(wù)器實(shí)例
Linux網(wǎng)絡(luò)編程--10. 原始套接字 --11. 后記
10. 原始套接字
10.1 原始套接字的創(chuàng)建
10.2 一個(gè)原始套接字的實(shí)例
10.3 總結(jié)
11. 后記


學(xué)習(xí)任何知識(shí)都不能光看不練。必須動(dòng)手練習(xí),對(duì)于這些函數(shù),自己寫(xiě)個(gè)小程序測(cè)試一下其用法就會(huì)很明了了。

論壇徽章:
0
33 [報(bào)告]
發(fā)表于 2007-02-04 15:13 |只看該作者

Linux下上網(wǎng)方法總結(jié)

目前大家用到的上網(wǎng)方法無(wú)非如下幾種:電話撥號(hào)、ADSL、局域網(wǎng)共享上網(wǎng)。

下面分別說(shuō)明在Linux下各種上網(wǎng)方法
1、電話撥號(hào)網(wǎng)絡(luò)設(shè)置
1)打開(kāi)一個(gè)命令終端,運(yùn)行配置命令wvdialconf,此命令將設(shè)置撥號(hào)上網(wǎng)的各參數(shù),保存在文件/etc/wvdial.conf里,文件內(nèi)容如下:
[Dialer Defaults]
Init1 = ATZ
Init2 = ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
Modem Type = Analog Modem
Baud = 115200
New PPPD = yes
Modem = /dev/modem
ISDN = 0
; Phone =
; Password =
; Username =

2)手動(dòng)編輯此文件,比如用vi命令,vi /etc/wvdial.conf
把此文件的最后幾行前面的注釋符號(hào)去掉,后面的值改成電話撥號(hào)的幾個(gè)參數(shù)(這三個(gè)參數(shù)可以打電信的客戶號(hào)碼問(wèn)),如下:
Phone = 撥號(hào)上網(wǎng)的電話號(hào)碼
Password = 上網(wǎng)的用戶名
Username = 上網(wǎng)的密碼

至此,電話撥號(hào)上網(wǎng)已經(jīng)設(shè)置完成
3)運(yùn)行命令來(lái)開(kāi)始撥號(hào),命令如下:
pon wvdial

連接成功后就可以開(kāi)心上網(wǎng)了。

2、ADSL上網(wǎng)設(shè)置
運(yùn)行一個(gè)ADSL配置命令pppoeconf。
按照界面提示一步步設(shè)置即可
程序?qū)⒆詣?dòng)檢測(cè)系統(tǒng)可用的網(wǎng)卡,如下圖:

一般應(yīng)該只出現(xiàn)eth0, eth1之類的,因?yàn)槲已b了VMware虛擬機(jī),所以有vmnet1、vmnet8之類的虛擬網(wǎng)卡出現(xiàn) 。

當(dāng)然這里要選“是”以便繼續(xù)設(shè)置。

系統(tǒng)自動(dòng)檢測(cè)ADSL設(shè)備。

允許程序設(shè)置一些默認(rèn)參數(shù),當(dāng)然你也可以選擇“否”,按照你自己的特殊參數(shù)來(lái)設(shè)置。但目前國(guó)內(nèi)的ADSL可能沒(méi)什么差別,所以選默認(rèn)值足夠了。

這里輸入ADSL的帳號(hào)。

這里輸入ADSL帳號(hào)對(duì)應(yīng)的密碼。下面的都選“是”應(yīng)該可以了。



如果你只是偶爾用一下ADSL上網(wǎng),那么這里可以選擇“否”,如果每次都是用ADSL上網(wǎng)并且不限時(shí)上網(wǎng)(即包月上網(wǎng)那種),就選擇“是”將會(huì)開(kāi)機(jī)自動(dòng)啟動(dòng)ADSL網(wǎng)絡(luò)。

這里說(shuō)明了以后手工啟動(dòng)ADSL網(wǎng)絡(luò)的方法,看到了沒(méi)?輸入命令pon dsl-provider即可啟動(dòng)上網(wǎng),poff就可以斷開(kāi)網(wǎng)絡(luò)連接了。

配置完成后在/etc/ppp/目錄下生成ppp相關(guān)的文件,當(dāng)然/etc/ppp/peers/dsl-provider文件里記錄了所有參數(shù),你可以自己修改。
同時(shí)在/etc/init.d目錄里也生成 了幾個(gè)文件:
/etc/init.d/pppd-dns
/etc/init.d/ppp
/etc/init.d/pppstatus-clean
/etc/init.d/pppstatus

所以你也可以用/etc/init.d/ppp start命令來(lái)啟動(dòng)網(wǎng)絡(luò)。和pon dsl-provider一樣。
網(wǎng)絡(luò)啟動(dòng)了就可以開(kāi)心上網(wǎng)了。
/************關(guān)于本文檔********************************************
*filename: Linux下上網(wǎng)方法總結(jié)
*purpose: 說(shuō)明了Linux下幾種上網(wǎng)方法的設(shè)置:電話撥號(hào)、ADSL、局域網(wǎng)共享上網(wǎng)
*wrote by: zhoulifa(zhoulifa@163.com) 周立發(fā)(http://zhoulifa.bokee.com)
Linux愛(ài)好者 Linux知識(shí)傳播者 SOHO族 開(kāi)發(fā)者 最擅長(zhǎng)C語(yǔ)言
*date time:2007-01-28 18:02
*Note: 任何人可以任意復(fù)制代碼并運(yùn)用這些文檔,當(dāng)然包括你的商業(yè)用途
* 但請(qǐng)遵循GPL
*Thanks to: Google.com
*Hope:希望越來(lái)越多的人貢獻(xiàn)自己的力量,為科學(xué)技術(shù)發(fā)展出力
* 科技站在巨人的肩膀上進(jìn)步更快!感謝有開(kāi)源前輩的貢獻(xiàn)!
*********************************************************************/

3、局域網(wǎng)共享上網(wǎng)設(shè)置
一般來(lái)說(shuō)局域網(wǎng)里一定有一個(gè)作為路由的設(shè)備連接著互聯(lián)網(wǎng),其它局域網(wǎng)電腦只要設(shè)置好IP地址、網(wǎng)關(guān)、子網(wǎng)掩碼和DNS就可以上風(fēng)了。

最簡(jiǎn)單的方法就是設(shè)置網(wǎng)卡為DHCP動(dòng)態(tài)獲取方式,設(shè)置方法如下:
如果是Debian/Ubuntu系統(tǒng),則修改/etc/network/interfaces文件,把里面關(guān)于eth0(這是第一塊網(wǎng)卡,相應(yīng)地,eth1代表第二塊網(wǎng)卡)的改成如下即可:
auto eth0
iface eth0 inet dhcp

如果是Red Hat等其它的,好象是要修改/etc/sysconfig/network-scripts/ifcfg-eth0文件(太久不用這個(gè)版本了,所以記不太清楚),修改內(nèi)容如下:
DEVICE=eth0
BOOTPROTO=dhcp
onBOOT=yes

另一種方法就是按照管理員的要求,每臺(tái)電腦分配一個(gè)固定的IP地址,同樣是要修改上面提到的文件,比如/etc/network/interfaces,文件里關(guān)于eth0的內(nèi)容要改成下面的:
auto eth0
iface eth0 inet static
address 192.168.100.30
gateway 192.168.100.1
netmask 255.255.255.0

/etc/sysconfig/network-scripts/ifcfg-eth0要修改成如下方式:
DEVICE=eth0
BOOTPROTO=none
onBOOT=yes
IPADDR=192.168.100.30
NETMASK=255.255.255.0
GATEWAY=192.168.100.1

所有配置方法都有相關(guān)圖形界面可以用的,比如下圖:

但我是寫(xiě)程序的,所以比較喜歡用命令去配置或者自己動(dòng)手修改配置文件。因?yàn)橄到y(tǒng)所有東西除非是寫(xiě)在操作系統(tǒng)里,否則都是在文件里,由操作系統(tǒng)來(lái)讀取并執(zhí)行的。

論壇徽章:
0
34 [報(bào)告]
發(fā)表于 2007-02-04 15:14 |只看該作者

Linux網(wǎng)絡(luò)編程一步一步學(xué)-利用OpenSSL提供的SSL操作函數(shù)進(jìn)行加密通訊原始例子

首先,大家知道SSL這一目前“事實(shí)上的Internet加密標(biāo)準(zhǔn)” 吧?一般的網(wǎng)站是沒(méi)有用到SSL的,所以如果你用TCPDUMP就可以很容易地看到別人上網(wǎng)的帳號(hào)、密碼之類的,當(dāng)然,現(xiàn)在有些已經(jīng)改用安全通訊方式進(jìn)行驗(yàn)證了,比如google的郵件服務(wù)gmail,而象銀行、證券等行業(yè),從一開(kāi)始就要求用加密通訊,你在哪個(gè)銀行網(wǎng)站上輸入帳號(hào)和密碼后點(diǎn)擊提交不是通過(guò)加密方式提交的呢?事實(shí)上,SSL也正是在銀行這些行業(yè)的需求下才產(chǎn)生的。
現(xiàn)在大家經(jīng)常上網(wǎng)會(huì)上到一些https://開(kāi)頭的網(wǎng)站,那就是把SSL標(biāo)準(zhǔn)應(yīng)用到HTTP上從而變成了HTTPS。另外大家可能都不用telnet這個(gè)明文傳輸工具來(lái)進(jìn)行遠(yuǎn)程登錄了,都改用ssh了,ssh正是SSL的一個(gè)實(shí)現(xiàn),用來(lái)進(jìn)行遠(yuǎn)程加密通訊的。

其次,要在我們現(xiàn)有的TCP程序上加上SSL,你得安裝開(kāi)發(fā)包libssl-dev,這個(gè)包的描述是這樣的:
Package: libssl-dev
Priority: optional
Section: libdevel
Installed-Size: 5552
Maintainer: Debian OpenSSL Team
Architecture: i386
Source: openssl
Version: 0.9.8a-7ubuntu0.3
Depends: libssl0.9.8 (= 0.9.8a-7ubuntu0.3), zlib1g-dev
Conflicts: ssleay (<< 0.9.2b), libssl08-dev, libssl09-dev, libssl095a-dev, libssl096-dev
Filename: pool/main/o/openssl/libssl-dev_0.9.8a-7ubuntu0.3_i386.deb
Size: 2023440
MD5sum: 3c4052d07abe7d7984a774ca815ba4cf
SHA1: 29145b66372613e78c37d9ce0de6a7d1cfc7bac0
SHA256: 9e86aa1174a45e4f61e5afcb56d485ea60f90e31b0ecaf2bf31f426f7eb8c6eb
Description: SSL development libraries, header files and documentation
libssl and libcrypt development libraries, header files and manpages
.
It is part of the OpenSSL implementation of SSL.
Bugs: mailto:ubuntu-users@lists.ubuntu.com
Origin: Ubuntu

Package: libssl-dev
Priority: optional
Section: libdevel
Installed-Size: 5548
Maintainer: Debian OpenSSL Team
Architecture: i386
Source: openssl
Version: 0.9.8a-7build1
Depends: libssl0.9.8 (= 0.9.8a-7build1), zlib1g-dev
Conflicts: ssleay (<< 0.9.2b), libssl08-dev, libssl09-dev, libssl095a-dev, libssl096-dev
Filename: pool/main/o/openssl/libssl-dev_0.9.8a-7build1_i386.deb
Size: 2022142
MD5sum: c9b989aebbae4f6f5dbde67207858023
Description: SSL development libraries, header files and documentation
libssl and libcrypt development libraries, header files and manpages
.
It is part of the OpenSSL implementation of SSL.
Bugs: mailto:ubuntu-users@lists.ubuntu.com
Origin: Ubuntu

也就是說(shuō)這個(gè)libssl-dev包是庫(kù)函數(shù)、頭文件以及相關(guān)編程說(shuō)明文檔的集合。

安裝完成之后在/usr/share/doc/libssl-dev/demos目錄下有一些編程示例。你可以參照里面的文檔自己來(lái)寫(xiě)加密通訊程序。

/************關(guān)于本文檔********************************************
*filename: Linux網(wǎng)絡(luò)編程一步一步學(xué)-利用OpenSSL提供的SSL操作函數(shù)進(jìn)行加密通訊原始例子
*purpose: 說(shuō)明了如果在Linux下利用OpenSSL庫(kù)函數(shù)進(jìn)行SSL加密通訊程序開(kāi)發(fā)
*tidied by: zhoulifa(zhoulifa@163.com) 周立發(fā)(http://zhoulifa.bokee.com)
Linux愛(ài)好者 Linux知識(shí)傳播者 SOHO族 開(kāi)發(fā)者 最擅長(zhǎng)C語(yǔ)言
*date time:2007-01-28 19:00
*Note: 任何人可以任意復(fù)制代碼并運(yùn)用這些文檔,當(dāng)然包括你的商業(yè)用途
* 但請(qǐng)遵循GPL
*Thanks to: Google.com
*Hope:希望越來(lái)越多的人貢獻(xiàn)自己的力量,為科學(xué)技術(shù)發(fā)展出力
* 科技站在巨人的肩膀上進(jìn)步更快!感謝有開(kāi)源前輩的貢獻(xiàn)!
*********************************************************************/

比如/usr/share/doc/libssl-dev/demos/bio目錄下提供的一個(gè)服務(wù)器端例子,代碼如下:

  1. /* NOCW */
  2. /* demos/bio/saccept.c */

  3. /* A minimal program to server an SSL connection.
  4. * It uses blocking.
  5. * saccept host:port
  6. * host is the interface IP to use.  If any interface, use *:port
  7. * The default it *:4433
  8. *
  9. * cc -I../../include saccept.c -L../.. -lssl -lcrypto
  10. */

  11. #include <stdio.h>
  12. #include <signal.h>
  13. #include <openssl/err.h>
  14. #include <openssl/ssl.h>

  15. #define CERT_FILE    "server.pem"

  16. BIO *in=NULL;

  17. void close_up()
  18.     {
  19.     if (in != NULL)
  20.         BIO_free(in);
  21.     }

  22. int main(argc,argv)
  23. int argc;
  24. char *argv[];
  25.     {
  26.     char *port=NULL;
  27.     BIO *ssl_bio,*tmp;
  28.     SSL_CTX *ctx;
  29.     SSL *ssl;
  30.     char buf[512];
  31.     int ret=1,i;

  32.         if (argc <= 1)
  33.         port="*:4433";
  34.     else
  35.         port=argv[1];

  36.     signal(SIGINT,close_up);

  37.     SSL_load_error_strings();

  38. #ifdef WATT32
  39.     dbug_init();
  40.     sock_init();
  41. #endif

  42.     /* Add ciphers and message digests */
  43.     OpenSSL_add_ssl_algorithms();

  44.     ctx=SSL_CTX_new(SSLv23_server_method());
  45.     if (!SSL_CTX_use_certificate_file(ctx,CERT_FILE,SSL_FILETYPE_PEM))
  46.         goto err;
  47.     if (!SSL_CTX_use_PrivateKey_file(ctx,CERT_FILE,SSL_FILETYPE_PEM))
  48.         goto err;
  49.     if (!SSL_CTX_check_private_key(ctx))
  50.         goto err;

  51.     /* Setup server side SSL bio */
  52.     ssl=SSL_new(ctx);
  53.     ssl_bio=BIO_new_ssl(ctx,0);

  54.     if ((in=BIO_new_accept(port)) == NULL) goto err;

  55.     /* This means that when a new connection is acceptede on 'in',
  56.      * The ssl_bio will be 'dupilcated' and have the new socket
  57.      * BIO push into it.  Basically it means the SSL BIO will be
  58.      * automatically setup */
  59.     BIO_set_accept_bios(in,ssl_bio);

  60. again:
  61.     /* The first call will setup the accept socket, and the second
  62.      * will get a socket.  In this loop, the first actual accept
  63.      * will occur in the BIO_read() function. */

  64.     if (BIO_do_accept(in) <= 0) goto err;

  65.     for (;;)
  66.         {
  67.         i=BIO_read(in,buf,512);
  68.         if (i == 0)
  69.             {
  70.             /* If we have finished, remove the underlying
  71.              * BIO stack so the next time we call any function
  72.              * for this BIO, it will attempt to do an
  73.              * accept */
  74.             printf("Done\n");
  75.             tmp=BIO_pop(in);
  76.             BIO_free_all(tmp);
  77.             goto again;
  78.             }
  79.         if (i < 0) goto err;
  80.         fwrite(buf,1,i,stdout);
  81.         fflush(stdout);
  82.         }

  83.     ret=0;
  84. err:
  85.     if (ret)
  86.         {
  87.         ERR_print_errors_fp(stderr);
  88.         }
  89.     if (in != NULL) BIO_free(in);
  90.     exit(ret);
  91.     return(!ret);
  92.     }
復(fù)制代碼

對(duì)應(yīng)的一個(gè)客戶端例子代碼如下:

  1. /* NOCW */
  2. /* demos/bio/sconnect.c */

  3. /* A minimal program to do SSL to a passed host and port.
  4. * It is actually using non-blocking IO but in a very simple manner
  5. * sconnect host:port - it does a 'GET / HTTP/1.0'
  6. *
  7. * cc -I../../include sconnect.c -L../.. -lssl -lcrypto
  8. */
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <unistd.h>
  12. #include <openssl/err.h>
  13. #include <openssl/ssl.h>

  14. extern int errno;

  15. int main(argc,argv)
  16. int argc;
  17. char *argv[];
  18.     {
  19.     char *host;
  20.     BIO *out;
  21.     char buf[1024*10],*p;
  22.     SSL_CTX *ssl_ctx=NULL;
  23.     SSL *ssl;
  24.     BIO *ssl_bio;
  25.     int i,len,off,ret=1;

  26.     if (argc <= 1)
  27.         host="localhost:4433";
  28.     else
  29.         host=argv[1];

  30. #ifdef WATT32
  31.     dbug_init();
  32.     sock_init();
  33. #endif

  34.     /* Lets get nice error messages */
  35.     SSL_load_error_strings();

  36.     /* Setup all the global SSL stuff */
  37.     OpenSSL_add_ssl_algorithms();
  38.     ssl_ctx=SSL_CTX_new(SSLv23_client_method());

  39.     /* Lets make a SSL structure */
  40.     ssl=SSL_new(ssl_ctx);
  41.     SSL_set_connect_state(ssl);

  42.     /* Use it inside an SSL BIO */
  43.     ssl_bio=BIO_new(BIO_f_ssl());
  44.     BIO_set_ssl(ssl_bio,ssl,BIO_CLOSE);

  45.     /* Lets use a connect BIO under the SSL BIO */
  46.     out=BIO_new(BIO_s_connect());
  47.     BIO_set_conn_hostname(out,host);
  48.     BIO_set_nbio(out,1);
  49.     out=BIO_push(ssl_bio,out);

  50.     p="GET / HTTP/1.0\r\n\r\n";
  51.     len=strlen(p);

  52.     off=0;
  53.     for (;;)
  54.         {
  55.         i=BIO_write(out,&(p[off]),len);
  56.         if (i <= 0)
  57.             {
  58.             if (BIO_should_retry(out))
  59.                 {
  60.                 fprintf(stderr,"write DELAY\n");
  61.                 sleep(1);
  62.                 continue;
  63.                 }
  64.             else
  65.                 {
  66.                 goto err;
  67.                 }
  68.             }
  69.         off+=i;
  70.         len-=i;
  71.         if (len <= 0) break;
  72.         }

  73.     for (;;)
  74.         {
  75.         i=BIO_read(out,buf,sizeof(buf));
  76.         if (i == 0) break;
  77.         if (i < 0)
  78.             {
  79.             if (BIO_should_retry(out))
  80.                 {
  81.                 fprintf(stderr,"read DELAY\n");
  82.                 sleep(1);
  83.                 continue;
  84.                 }
  85.             goto err;
  86.             }
  87.         fwrite(buf,1,i,stdout);
  88.         }

  89.     ret=1;

  90.     if (0)
  91.         {
  92. err:
  93.         if (ERR_peek_error() == 0) /* system call error */
  94.             {
  95.             fprintf(stderr,"errno=%d ",errno);
  96.             perror("error");
  97.             }
  98.         else
  99.             ERR_print_errors_fp(stderr);
  100.         }
  101.     BIO_free_all(out);
  102.     if (ssl_ctx != NULL) SSL_CTX_free(ssl_ctx);
  103.     exit(!ret);
  104.     return(ret);
  105.     }
復(fù)制代碼

編譯程序里象一般的gcc命令一樣,但需要鏈接ssl庫(kù),比如
gcc -Wall saccept.c -o sslserver -lssl
gcc -Wall sconnect.c -o sslclient -l ssl


【作者: 周立發(fā)】【訪問(wèn)統(tǒng)計(jì):24】【2007年01月28日 星期日 18:47】【注冊(cè)】【打印】
Trackback

你可以使用這個(gè)鏈接引用該篇文章 http://publishblog.blogchina.com/blog/tb.b?diaryID=6074014
回復(fù)
發(fā)布人:

論壇徽章:
0
35 [報(bào)告]
發(fā)表于 2007-02-04 15:17 |只看該作者

Linux網(wǎng)絡(luò)編程一步一步學(xué)-IPv6下網(wǎng)絡(luò)編程步驟

論壇徽章:
0
36 [報(bào)告]
發(fā)表于 2007-02-04 15:27 |只看該作者

Linux網(wǎng)絡(luò)編程一步一步學(xué)-HTTPS客戶端程序示例

源代碼如下:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <errno.h>
  7. #include <unistd.h>
  8. #include <netinet/in.h>
  9. #include <limits.h>
  10. #include <netdb.h>
  11. #include <arpa/inet.h>
  12. #include <ctype.h>
  13. #include <openssl/crypto.h>
  14. #include <openssl/ssl.h>
  15. #include <openssl/err.h>
  16. #include <openssl/rand.h>

  17. #define DEBUG 1

  18. /********************************************
  19. 功能:搜索字符串右邊起的第一個(gè)匹配字符
  20. ********************************************/
  21. char *Rstrchr(char *s, char x)
  22. {
  23.     int i = strlen(s);
  24.     if (!(*s))
  25.         return 0;
  26.     while (s[i - 1])
  27.         if (strchr(s + (i - 1), x))
  28.             return (s + (i - 1));
  29.         else
  30.             i--;
  31.     return 0;
  32. }

  33. /**************************************************************
  34. 功能:從字符串src中分析出網(wǎng)站地址和端口,并得到用戶要下載的文件
  35. ***************************************************************/
  36. void GetHost(char *src, char *web, char *file, int *port)
  37. {
  38.     char *pA;
  39.     char *pB;
  40.     memset(web, 0, sizeof(web));
  41.     memset(file, 0, sizeof(file));
  42.     *port = 0;
  43.     if (!(*src))
  44.         return;
  45.     pA = src;
  46.     if (!strncmp(pA, "http://", strlen("http://")))
  47.         pA = src + strlen("http://");
  48.     else if (!strncmp(pA, "https://", strlen("https://")))
  49.         pA = src + strlen("https://");
  50.     pB = strchr(pA, '/');
  51.     if (pB) {
  52.         memcpy(web, pA, strlen(pA) - strlen(pB));
  53.         if (pB + 1) {
  54.             memcpy(file, pB + 1, strlen(pB) - 1);
  55.             file[strlen(pB) - 1] = 0;
  56.         }
  57.     } else
  58.         memcpy(web, pA, strlen(pA));
  59.     if (pB)
  60.         web[strlen(pA) - strlen(pB)] = 0;
  61.     else
  62.         web[strlen(pA)] = 0;
  63.     pA = strchr(web, ':');
  64.     if (pA)
  65.         *port = atoi(pA + 1);
  66.     else
  67.         *port = 443;
  68. }

  69. /************關(guān)于本文檔********************************************
  70. *filename: https-client.c
  71. *purpose: 演示HTTPS客戶端編程方法
  72. *wrote by: zhoulifa(zhoulifa@163.com) 周立發(fā)(http://zhoulifa.bokee.com)
  73. Linux愛(ài)好者 Linux知識(shí)傳播者 SOHO族 開(kāi)發(fā)者 最擅長(zhǎng)C語(yǔ)言
  74. *date time:2007-01-30 20:06
  75. *Note: 任何人可以任意復(fù)制代碼并運(yùn)用這些文檔,當(dāng)然包括你的商業(yè)用途
  76. * 但請(qǐng)遵循GPL
  77. *Thanks to:Google
  78. *Hope:希望越來(lái)越多的人貢獻(xiàn)自己的力量,為科學(xué)技術(shù)發(fā)展出力
  79. * 科技站在巨人的肩膀上進(jìn)步更快!感謝有開(kāi)源前輩的貢獻(xiàn)!
  80. *********************************************************************/

  81. int main(int argc, char *argv[])
  82. {
  83.     int sockfd, ret;
  84.     char buffer[1024];
  85.     struct sockaddr_in server_addr;
  86.     struct hostent *host;
  87.     int portnumber, nbytes;
  88.     char host_addr[256];
  89.     char host_file[1024];
  90.     char local_file[256];
  91.     FILE *fp;
  92.     char request[1024];
  93.     int send, totalsend;
  94.     int i;
  95.     char *pt;
  96.     SSL *ssl;
  97.     SSL_CTX *ctx;

  98.     if (argc != 2) {
  99.         if (DEBUG)
  100.             fprintf(stderr, "Usage:%s webpage-address\a\n", argv[0]);
  101.         exit(1);
  102.     }
  103.     if (DEBUG)
  104.         printf("parameter.1 is: %s\n", argv[1]);

  105.     GetHost(argv[1], host_addr, host_file, &portnumber);        /*分析網(wǎng)址、端口、文件名等 */
  106.     if (DEBUG)
  107.         printf("webhost:%s\n", host_addr);
  108.     if (DEBUG)
  109.         printf("hostfile:%s\n", host_file);
  110.     if (DEBUG)
  111.         printf("portnumber:%d\n\n", portnumber);

  112.     if ((host = gethostbyname(host_addr)) == NULL) {        /*取得主機(jī)IP地址 */
  113.         if (DEBUG)
  114.             fprintf(stderr, "Gethostname error, %s\n", strerror(errno));
  115.         exit(1);
  116.     }

  117.     /* 客戶程序開(kāi)始建立 sockfd描述符 */
  118.     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {        /*建立SOCKET連接 */
  119.         if (DEBUG)
  120.             fprintf(stderr, "Socket Error:%s\a\n", strerror(errno));
  121.         exit(1);
  122.     }

  123.     /* 客戶程序填充服務(wù)端的資料 */
  124.     bzero(&server_addr, sizeof(server_addr));
  125.     server_addr.sin_family = AF_INET;
  126.     server_addr.sin_port = htons(portnumber);
  127.     server_addr.sin_addr = *((struct in_addr *) host->h_addr);

  128.     /* 客戶程序發(fā)起連接請(qǐng)求 */
  129.     if (connect(sockfd, (struct sockaddr *) (&server_addr), sizeof(struct sockaddr)) == -1) {        /*連接網(wǎng)站 */
  130.         if (DEBUG)
  131.             fprintf(stderr, "Connect Error:%s\a\n", strerror(errno));
  132.         exit(1);
  133.     }

  134.     /* SSL初始化 */
  135.     SSL_library_init();
  136.     SSL_load_error_strings();
  137.     ctx = SSL_CTX_new(SSLv23_client_method());
  138.     if (ctx == NULL) {
  139.         ERR_print_errors_fp(stderr);
  140.         exit(1);
  141.     }

  142.     ssl = SSL_new(ctx);
  143.     if (ssl == NULL) {
  144.         ERR_print_errors_fp(stderr);
  145.         exit(1);
  146.     }

  147.     /* 把socket和SSL關(guān)聯(lián) */
  148.     ret = SSL_set_fd(ssl, sockfd);
  149.     if (ret == 0) {
  150.         ERR_print_errors_fp(stderr);
  151.         exit(1);
  152.     }

  153.     RAND_poll();
  154.     while (RAND_status() == 0) {
  155.         unsigned short rand_ret = rand() % 65536;
  156.         RAND_seed(&rand_ret, sizeof(rand_ret));
  157.     }

  158.     ret = SSL_connect(ssl);
  159.     if (ret != 1) {
  160.         ERR_print_errors_fp(stderr);
  161.         exit(1);
  162.     }

  163.     sprintf(request, "GET /%s HTTP/1.1\r\nAccept: */*\r\nAccept-Language: zh-cn\r\n\
  164. User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)\r\n\
  165. Host: %s:%d\r\nConnection: Close\r\n\r\n", host_file, host_addr,
  166.             portnumber);
  167.     if (DEBUG)
  168.         printf("%s", request);        /*準(zhǔn)備request,將要發(fā)送給主機(jī) */

  169.     /*取得真實(shí)的文件名 */
  170.     if (host_file && *host_file)
  171.         pt = Rstrchr(host_file, '/');
  172.     else
  173.         pt = 0;

  174.     memset(local_file, 0, sizeof(local_file));
  175.     if (pt && *pt) {
  176.         if ((pt + 1) && *(pt + 1))
  177.             strcpy(local_file, pt + 1);
  178.         else
  179.             memcpy(local_file, host_file, strlen(host_file) - 1);
  180.     } else if (host_file && *host_file)
  181.         strcpy(local_file, host_file);
  182.     else
  183.         strcpy(local_file, "index.html");
  184.     if (DEBUG)
  185.         printf("local filename to write:%s\n\n", local_file);

  186.     /*發(fā)送https請(qǐng)求request */
  187.     send = 0;
  188.     totalsend = 0;
  189.     nbytes = strlen(request);
  190.     while (totalsend < nbytes) {
  191.         send = SSL_write(ssl, request + totalsend, nbytes - totalsend);
  192.         if (send == -1) {
  193.             if (DEBUG)
  194.                 ERR_print_errors_fp(stderr);
  195.             exit(0);
  196.         }
  197.         totalsend += send;
  198.         if (DEBUG)
  199.             printf("%d bytes send OK!\n", totalsend);
  200.     }

  201.     fp = fopen(local_file, "a");
  202.     if (!fp) {
  203.         if (DEBUG)
  204.             printf("create file error! %s\n", strerror(errno));
  205.         return 0;
  206.     }
  207.     if (DEBUG)
  208.         printf("\nThe following is the response header:\n");
  209.     i = 0;
  210.     /* 連接成功了,接收https響應(yīng),response */
  211.     while ((nbytes = SSL_read(ssl, buffer, 1)) == 1) {
  212.         if (i < 4) {
  213.             if (buffer[0] == '\r' || buffer[0] == '\n')
  214.                 i++;
  215.             else
  216.                 i = 0;
  217.             if (DEBUG)
  218.                 printf("%c", buffer[0]);        /*把https頭信息打印在屏幕上 */
  219.         } else {
  220.             fwrite(buffer, 1, 1, fp);        /*將https主體信息寫(xiě)入文件 */
  221.             i++;
  222.             if (i % 1024 == 0)
  223.                 fflush(fp);        /*每1K時(shí)存盤(pán)一次 */
  224.         }
  225.     }
  226.     fclose(fp);
  227.     /* 結(jié)束通訊 */
  228.     ret = SSL_shutdown(ssl);
  229.     if (ret != 1) {
  230.         ERR_print_errors_fp(stderr);
  231.         exit(1);
  232.     }
  233.     close(sockfd);
  234.     SSL_free(ssl);
  235.     SSL_CTX_free(ctx);
  236.     ERR_free_strings();
  237.     exit(0);
  238. }
復(fù)制代碼

編譯此程序用下列命令:
gcc -Wall https-client.c -lssl -o httpsclient

運(yùn)行此程序來(lái)取得HTTPS服務(wù)器上的頁(yè)面,比如:
./httpsclient https://127.0.0.1/test.html

關(guān)鍵之處在于建立socket之后的SSL相關(guān)初始化以及中間的recv/send用SSL_read和SSL_write代替,最后記得釋放SSL資源即可。
可以對(duì)比之前的文章來(lái)發(fā)現(xiàn)異同:
HTTP協(xié)議的C語(yǔ)言編程實(shí)現(xiàn)實(shí)例

論壇徽章:
0
37 [報(bào)告]
發(fā)表于 2007-02-04 15:29 |只看該作者

OpenSSL體系下使用密鑰數(shù)字證書(shū)等

首先得安裝OpenSSL軟件包openssl,安裝了這個(gè)軟件包之后,我們可以做這些事情:
  o  Creation of RSA, DH and DSA Key Parameters # 創(chuàng)建密鑰 key
  o  Creation of X.509 Certificates, CSRs and CRLs # 創(chuàng)建證書(shū)
  o  Calculation of Message Digests                #
  o  Encryption and Decryption with Ciphers # 加密、解密
  o  SSL/TLS Client and Server Tests        # SSL 服務(wù)器端/客戶端測(cè)試
  o  Handling of S/MIME signed or encrypted Mail  # 處理簽名或加密了的郵件

1、生成RSA密鑰的方法
openssl genrsa -des3 -out privkey.pem 2048

這個(gè)命令會(huì)生成一個(gè)2048位的密鑰,同時(shí)有一個(gè)des3方法加密的密碼,如果你不想要每次都輸入密碼,可以改成:
openssl genrsa -out privkey.pem 2048

建議用2048位密鑰,少于此可能會(huì)不安全或很快將不安全。

2、生成一個(gè)證書(shū)請(qǐng)求
openssl req -new -key privkey.pem -out cert.csr

這個(gè)命令將會(huì)生成一個(gè)證書(shū)請(qǐng)求,當(dāng)然,用到了前面生成的密鑰privkey.pem文件
這里將生成一個(gè)新的文件cert.csr,即一個(gè)證書(shū)請(qǐng)求文件,你可以拿著這個(gè)文件去數(shù)字證書(shū)頒發(fā)機(jī)構(gòu)(即CA)申請(qǐng)一個(gè)數(shù)字證書(shū)。CA會(huì)給你一個(gè)新的文件cacert.pem,那才是你的數(shù)字證書(shū)。

如果是自己做測(cè)試,那么證書(shū)的申請(qǐng)機(jī)構(gòu)和頒發(fā)機(jī)構(gòu)都是自己。就可以用下面這個(gè)命令來(lái)生成證書(shū):
openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095

這個(gè)命令將用上面生成的密鑰privkey.pem生成一個(gè)數(shù)字證書(shū)cacert.pem

3、使用數(shù)字證書(shū)和密鑰
有了privkey.pem和cacert.pem文件后就可以在自己的程序中使用了,比如做一個(gè)加密通訊的服務(wù)器

論壇徽章:
0
38 [報(bào)告]
發(fā)表于 2007-02-04 15:32 |只看該作者

Linux網(wǎng)絡(luò)編程一步一步學(xué)-epoll同時(shí)處理海量連接的代碼

如果你是做大型項(xiàng)目的,比如同時(shí)要求上萬(wàn)人在線的某種程序,比如在線游戲、在線聊天,那怕是一個(gè)最簡(jiǎn)單的支持上萬(wàn)人同時(shí)在線的WEB服務(wù)器。用原來(lái)的方法都比較困難實(shí)現(xiàn)的。
下面這段代碼就可以支持9997個(gè)連接同時(shí)在線,當(dāng)然你可以修改宏定義以支持更多的連接:
#define MAXEPOLLSIZE 10000

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <errno.h>
  4. #include <string.h>
  5. #include <sys/types.h>
  6. #include <netinet/in.h>
  7. #include <sys/socket.h>
  8. #include <sys/wait.h>
  9. #include <unistd.h>
  10. #include <arpa/inet.h>
  11. #include <openssl/ssl.h>
  12. #include <openssl/err.h>
  13. #include <fcntl.h>
  14. #include <sys/epoll.h>
  15. #include <sys/time.h>
  16. #include <sys/resource.h>


  17. #define MAXBUF 1024
  18. #define MAXEPOLLSIZE 10000

  19. /*
  20. setnonblocking - 設(shè)置句柄為非阻塞方式
  21. */
  22. int setnonblocking(int sockfd)
  23. {
  24.     if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1) {
  25.         return -1;
  26.     }
  27.     return 0;
  28. }

  29. /*
  30. handle_message - 處理每個(gè) socket 上的消息收發(fā)
  31. */
  32. int handle_message(int new_fd)
  33. {
  34.     char buf[MAXBUF + 1];
  35.     int len;
  36.     /* 開(kāi)始處理每個(gè)新連接上的數(shù)據(jù)收發(fā) */
  37.     bzero(buf, MAXBUF + 1);
  38.     /* 接收客戶端的消息 */
  39.     len = recv(new_fd, buf, MAXBUF, 0);
  40.     if (len > 0)
  41.         printf
  42.             ("%d接收消息成功:'%s',共%d個(gè)字節(jié)的數(shù)據(jù)\n",
  43.              new_fd, buf, len);
  44.     else {
  45.         if (len < 0)
  46.             printf
  47.                 ("消息接收失!錯(cuò)誤代碼是%d,錯(cuò)誤信息是'%s'\n",
  48.                  errno, strerror(errno));
  49.         close(new_fd);
  50.         return -1;
  51.     }
  52.     /* 處理每個(gè)新連接上的數(shù)據(jù)收發(fā)結(jié)束 */
  53.     return len;
  54. }
  55. /************關(guān)于本文檔********************************************
  56. *filename: epoll-server.c
  57. *purpose: 演示epoll處理海量socket連接的方法
  58. *wrote by: zhoulifa(zhoulifa@163.com) 周立發(fā)(http://zhoulifa.bokee.com)
  59. Linux愛(ài)好者 Linux知識(shí)傳播者 SOHO族 開(kāi)發(fā)者 最擅長(zhǎng)C語(yǔ)言
  60. *date time:2007-01-31 21:00
  61. *Note: 任何人可以任意復(fù)制代碼并運(yùn)用這些文檔,當(dāng)然包括你的商業(yè)用途
  62. * 但請(qǐng)遵循GPL
  63. *Thanks to:Google
  64. *Hope:希望越來(lái)越多的人貢獻(xiàn)自己的力量,為科學(xué)技術(shù)發(fā)展出力
  65. * 科技站在巨人的肩膀上進(jìn)步更快!感謝有開(kāi)源前輩的貢獻(xiàn)!
  66. *********************************************************************/
  67. int main(int argc, char **argv)
  68. {
  69.     int listener, new_fd, kdpfd, nfds, n, ret, curfds;
  70.     socklen_t len;
  71.     struct sockaddr_in my_addr, their_addr;
  72.     unsigned int myport, lisnum;
  73.     struct epoll_event ev;
  74.     struct epoll_event events[MAXEPOLLSIZE];
  75.     struct rlimit rt;

  76.     if (argv[1])
  77.         myport = atoi(argv[1]);
  78.     else
  79.         myport = 7838;

  80.     if (argv[2])
  81.         lisnum = atoi(argv[2]);
  82.     else
  83.         lisnum = 2;

  84.     /* 設(shè)置每個(gè)進(jìn)程允許打開(kāi)的最大文件數(shù) */
  85.     rt.rlim_max = rt.rlim_cur = MAXEPOLLSIZE;
  86.     if (setrlimit(RLIMIT_NOFILE, &rt) == -1) {
  87.         perror("setrlimit");
  88.         exit(1);
  89.     }
  90.     else printf("設(shè)置系統(tǒng)資源參數(shù)成功!\n");

  91.     /* 開(kāi)啟 socket 監(jiān)聽(tīng) */
  92.     if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
  93.         perror("socket");
  94.         exit(1);
  95.     } else
  96.         printf("socket 創(chuàng)建成功!\n");

  97.     setnonblocking(listener);

  98.     bzero(&my_addr, sizeof(my_addr));
  99.     my_addr.sin_family = PF_INET;
  100.     my_addr.sin_port = htons(myport);
  101.     if (argv[3])
  102.         my_addr.sin_addr.s_addr = inet_addr(argv[3]);
  103.     else
  104.         my_addr.sin_addr.s_addr = INADDR_ANY;

  105.     if (bind
  106.         (listener, (struct sockaddr *) &my_addr, sizeof(struct sockaddr))
  107.         == -1) {
  108.         perror("bind");
  109.         exit(1);
  110.     } else
  111.         printf("IP 地址和端口綁定成功\n");

  112.     if (listen(listener, lisnum) == -1) {
  113.         perror("listen");
  114.         exit(1);
  115.     } else
  116.         printf("開(kāi)啟服務(wù)成功!\n");

  117.     /* 創(chuàng)建 epoll 句柄,把監(jiān)聽(tīng) socket 加入到 epoll 集合里 */
  118.     kdpfd = epoll_create(MAXEPOLLSIZE);
  119.     len = sizeof(struct sockaddr_in);
  120.     ev.events = EPOLLIN | EPOLLET;
  121.     ev.data.fd = listener;
  122.     if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, listener, &ev) < 0) {
  123.         fprintf(stderr, "epoll set insertion error: fd=%d\n", listener);
  124.         return -1;
  125.     } else
  126.         printf("監(jiān)聽(tīng) socket 加入 epoll 成功!\n");
  127.     curfds = 1;
  128.     while (1) {
  129.         /* 等待有事件發(fā)生 */
  130.         nfds = epoll_wait(kdpfd, events, curfds, -1);
  131.         if (nfds == -1) {
  132.             perror("epoll_wait");
  133.             break;
  134.         }
  135.         /* 處理所有事件 */
  136.         for (n = 0; n < nfds; ++n) {
  137.             if (events[n].data.fd == listener) {
  138.                 new_fd = accept(listener, (struct sockaddr *) &their_addr,
  139.                                 &len);
  140.                 if (new_fd < 0) {
  141.                     perror("accept");
  142.                     continue;
  143.                 } else
  144.                     printf("有連接來(lái)自于: %d:%d, 分配的 socket 為:%d\n", inet_ntoa(their_addr.sin_addr), ntohs(their_addr.sin_port), new_fd);

  145.                 setnonblocking(new_fd);
  146.                 ev.events = EPOLLIN | EPOLLET;
  147.                 ev.data.fd = new_fd;
  148.                 if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, new_fd, &ev) < 0) {
  149.                     fprintf(stderr, "把 socket '%d' 加入 epoll 失!%s\n",
  150.                             new_fd, strerror(errno));
  151.                     return -1;
  152.                 }
  153.                 curfds++;
  154.             } else {
  155.                 ret = handle_message(events[n].data.fd);
  156.                 if (ret < 1 && errno != 11) {
  157.                     epoll_ctl(kdpfd, EPOLL_CTL_DEL, events[n].data.fd,
  158.                               &ev);
  159.                     curfds--;
  160.                 }
  161.             }
  162.         }
  163.     }
  164.     close(listener);
  165.     return 0;
  166. }
復(fù)制代碼

編譯此程序用命令:
gcc -Wall epoll-server.c -o server

運(yùn)行此程序需要具有管理員權(quán)限!
sudo ./server 7838 1

通過(guò)測(cè)試這一個(gè)服務(wù)器可能同時(shí)處理10000 -3 = 9997 個(gè)連接!

如果這是一個(gè)在線服務(wù)系統(tǒng),那么它可以支持9997人同時(shí)在線,比如游戲、聊天等。

論壇徽章:
0
39 [報(bào)告]
發(fā)表于 2007-02-04 15:43 |只看該作者

Linux網(wǎng)絡(luò)編程一步一步學(xué)-加密通訊協(xié)議SSL研究

服務(wù)器端源代碼如下:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <errno.h>
  4. #include <string.h>
  5. #include <sys/types.h>
  6. #include <netinet/in.h>
  7. #include <sys/socket.h>
  8. #include <sys/wait.h>
  9. #include <unistd.h>
  10. #include <arpa/inet.h>
  11. #include <openssl/ssl.h>
  12. #include <openssl/err.h>

  13. #define MAXBUF 1024
  14. /************關(guān)于本文檔********************************************
  15. *filename: ssl-server.c
  16. *purpose: 演示利用 OpenSSL 庫(kù)進(jìn)行基于 IP層的 SSL 加密通訊的方法,這是服務(wù)器端例子
  17. *wrote by: zhoulifa(zhoulifa@163.com) 周立發(fā)(http://zhoulifa.bokee.com)
  18. Linux愛(ài)好者 Linux知識(shí)傳播者 SOHO族 開(kāi)發(fā)者 最擅長(zhǎng)C語(yǔ)言
  19. *date time:2007-02-02 19:40
  20. *Note: 任何人可以任意復(fù)制代碼并運(yùn)用這些文檔,當(dāng)然包括你的商業(yè)用途
  21. * 但請(qǐng)遵循GPL
  22. *Thanks to:Google
  23. *Hope:希望越來(lái)越多的人貢獻(xiàn)自己的力量,為科學(xué)技術(shù)發(fā)展出力
  24. * 科技站在巨人的肩膀上進(jìn)步更快!感謝有開(kāi)源前輩的貢獻(xiàn)!
  25. *********************************************************************/
  26. int main(int argc, char **argv)
  27. {
  28.     int sockfd, new_fd;
  29.     socklen_t len;
  30.     struct sockaddr_in my_addr, their_addr;
  31.     unsigned int myport, lisnum;
  32.     char buf[MAXBUF + 1];
  33.     SSL_CTX *ctx;

  34.     if (argv[1])
  35.         myport = atoi(argv[1]);
  36.     else
  37.         myport = 7838;

  38.     if (argv[2])
  39.         lisnum = atoi(argv[2]);
  40.     else
  41.         lisnum = 2;

  42.     /* SSL 庫(kù)初始化 */
  43.     SSL_library_init();
  44.     /* 載入所有 SSL 算法 */
  45.     OpenSSL_add_all_algorithms();
  46.     /* 載入所有 SSL 錯(cuò)誤消息 */
  47.     SSL_load_error_strings();
  48.     /* 以 SSL V2 和 V3 標(biāo)準(zhǔn)兼容方式產(chǎn)生一個(gè) SSL_CTX ,即 SSL Content Text */
  49.     ctx = SSL_CTX_new(SSLv23_server_method());
  50.     /* 也可以用 SSLv2_server_method() 或 SSLv3_server_method() 單獨(dú)表示 V2 或 V3標(biāo)準(zhǔn) */
  51.     if (ctx == NULL) {
  52.         ERR_print_errors_fp(stdout);
  53.         exit(1);
  54.     }
  55.     /* 載入用戶的數(shù)字證書(shū), 此證書(shū)用來(lái)發(fā)送給客戶端。 證書(shū)里包含有公鑰 */
  56.     if (SSL_CTX_use_certificate_file(ctx, argv[4], SSL_FILETYPE_PEM) <= 0) {
  57.         ERR_print_errors_fp(stdout);
  58.         exit(1);
  59.     }
  60.     /* 載入用戶私鑰 */
  61.     if (SSL_CTX_use_PrivateKey_file(ctx, argv[5], SSL_FILETYPE_PEM) <= 0) {
  62.         ERR_print_errors_fp(stdout);
  63.         exit(1);
  64.     }
  65.     /* 檢查用戶私鑰是否正確 */
  66.     if (!SSL_CTX_check_private_key(ctx)) {
  67.         ERR_print_errors_fp(stdout);
  68.         exit(1);
  69.     }

  70.     /* 開(kāi)啟一個(gè) socket 監(jiān)聽(tīng) */
  71.     if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
  72.         perror("socket");
  73.         exit(1);
  74.     } else
  75.         printf("socket created\n");

  76.     bzero(&my_addr, sizeof(my_addr));
  77.     my_addr.sin_family = PF_INET;
  78.     my_addr.sin_port = htons(myport);
  79.     if (argv[3])
  80.         my_addr.sin_addr.s_addr = inet_addr(argv[3]);
  81.     else
  82.         my_addr.sin_addr.s_addr = INADDR_ANY;

  83.     if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr))
  84.         == -1) {
  85.         perror("bind");
  86.         exit(1);
  87.     } else
  88.         printf("binded\n");

  89.     if (listen(sockfd, lisnum) == -1) {
  90.         perror("listen");
  91.         exit(1);
  92.     } else
  93.         printf("begin listen\n");

  94.     while (1) {
  95.         SSL *ssl;
  96.         len = sizeof(struct sockaddr);
  97.         /* 等待客戶端連上來(lái) */
  98.         if ((new_fd =
  99.              accept(sockfd, (struct sockaddr *) &their_addr,
  100.                     &len)) == -1) {
  101.             perror("accept");
  102.             exit(errno);
  103.         } else
  104.             printf("server: got connection from %s, port %d, socket %d\n",
  105.                    inet_ntoa(their_addr.sin_addr),
  106.                    ntohs(their_addr.sin_port), new_fd);

  107.         /* 基于 ctx 產(chǎn)生一個(gè)新的 SSL */
  108.         ssl = SSL_new(ctx);
  109.         /* 將連接用戶的 socket 加入到 SSL */
  110.         SSL_set_fd(ssl, new_fd);
  111.         /* 建立 SSL 連接 */
  112.         if (SSL_accept(ssl) == -1) {
  113.             perror("accept");
  114.             close(new_fd);
  115.             break;
  116.         }

  117.         /* 開(kāi)始處理每個(gè)新連接上的數(shù)據(jù)收發(fā) */
  118.         bzero(buf, MAXBUF + 1);
  119.         strcpy(buf, "server->client");
  120.         /* 發(fā)消息給客戶端 */
  121.         len = SSL_write(ssl, buf, strlen(buf));

  122.         if (len <= 0) {
  123.             printf
  124.                 ("消息'%s'發(fā)送失敗!錯(cuò)誤代碼是%d,錯(cuò)誤信息是'%s'\n",
  125.                  buf, errno, strerror(errno));
  126.             goto finish;
  127.         } else
  128.             printf("消息'%s'發(fā)送成功,共發(fā)送了%d個(gè)字節(jié)!\n",
  129.                    buf, len);

  130.         bzero(buf, MAXBUF + 1);
  131.         /* 接收客戶端的消息 */
  132.         len = SSL_read(ssl, buf, MAXBUF);
  133.         if (len > 0)
  134.             printf("接收消息成功:'%s',共%d個(gè)字節(jié)的數(shù)據(jù)\n",
  135.                    buf, len);
  136.         else
  137.             printf
  138.                 ("消息接收失!錯(cuò)誤代碼是%d,錯(cuò)誤信息是'%s'\n",
  139.                  errno, strerror(errno));
  140.         /* 處理每個(gè)新連接上的數(shù)據(jù)收發(fā)結(jié)束 */
  141.       finish:
  142.         /* 關(guān)閉 SSL 連接 */
  143.         SSL_shutdown(ssl);
  144.         /* 釋放 SSL */
  145.         SSL_free(ssl);
  146.         /* 關(guān)閉 socket */
  147.         close(new_fd);
  148.     }

  149.     /* 關(guān)閉監(jiān)聽(tīng)的 socket */
  150.     close(sockfd);
  151.     /* 釋放 CTX */
  152.     SSL_CTX_free(ctx);
  153.     return 0;
  154. }
復(fù)制代碼

客戶端源代碼如下:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <errno.h>
  4. #include <sys/socket.h>
  5. #include <resolv.h>
  6. #include <stdlib.h>
  7. #include <netinet/in.h>
  8. #include <arpa/inet.h>
  9. #include <unistd.h>
  10. #include <openssl/ssl.h>
  11. #include <openssl/err.h>

  12. #define MAXBUF 1024

  13. void ShowCerts(SSL * ssl)
  14. {
  15.     X509 *cert;
  16.     char *line;

  17.     cert = SSL_get_peer_certificate(ssl);
  18.     if (cert != NULL) {
  19.         printf("數(shù)字證書(shū)信息:\n");
  20.         line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
  21.         printf("證書(shū): %s\n", line);
  22.         free(line);
  23.         line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
  24.         printf("頒發(fā)者: %s\n", line);
  25.         free(line);
  26.         X509_free(cert);
  27.     } else
  28.         printf("無(wú)證書(shū)信息!\n");
  29. }
  30. /************關(guān)于本文檔********************************************
  31. *filename: ssl-client.c
  32. *purpose: 演示利用 OpenSSL 庫(kù)進(jìn)行基于 IP層的 SSL 加密通訊的方法,這是客戶端例子
  33. *wrote by: zhoulifa(zhoulifa@163.com) 周立發(fā)(http://zhoulifa.bokee.com)
  34. Linux愛(ài)好者 Linux知識(shí)傳播者 SOHO族 開(kāi)發(fā)者 最擅長(zhǎng)C語(yǔ)言
  35. *date time:2007-02-02 20:10
  36. *Note: 任何人可以任意復(fù)制代碼并運(yùn)用這些文檔,當(dāng)然包括你的商業(yè)用途
  37. * 但請(qǐng)遵循GPL
  38. *Thanks to:Google
  39. *Hope:希望越來(lái)越多的人貢獻(xiàn)自己的力量,為科學(xué)技術(shù)發(fā)展出力
  40. * 科技站在巨人的肩膀上進(jìn)步更快!感謝有開(kāi)源前輩的貢獻(xiàn)!
  41. *********************************************************************/
  42. int main(int argc, char **argv)
  43. {
  44.     int sockfd, len;
  45.     struct sockaddr_in dest;
  46.     char buffer[MAXBUF + 1];
  47.     SSL_CTX *ctx;
  48.     SSL *ssl;

  49.     if (argc != 3) {
  50.         printf
  51.             ("參數(shù)格式錯(cuò)誤!正確用法如下:\n\t\t%s IP地址 端口\n\t比如:\t%s 127.0.0.1 80\n此程序用來(lái)從某個(gè) IP 地址的服務(wù)器某個(gè)端口接收最多 MAXBUF 個(gè)字節(jié)的消息",
  52.              argv[0], argv[0]);
  53.         exit(0);
  54.     }

  55.     /* SSL 庫(kù)初始化,參看 ssl-server.c 代碼 */
  56.     SSL_library_init();
  57.     OpenSSL_add_all_algorithms();
  58.     SSL_load_error_strings();
  59.     ctx = SSL_CTX_new(SSLv23_client_method());
  60.     if (ctx == NULL) {
  61.         ERR_print_errors_fp(stdout);
  62.         exit(1);
  63.     }

  64.     /* 創(chuàng)建一個(gè) socket 用于 tcp 通信 */
  65.     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  66.         perror("Socket");
  67.         exit(errno);
  68.     }
  69.     printf("socket created\n");

  70.     /* 初始化服務(wù)器端(對(duì)方)的地址和端口信息 */
  71.     bzero(&dest, sizeof(dest));
  72.     dest.sin_family = AF_INET;
  73.     dest.sin_port = htons(atoi(argv[2]));
  74.     if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0) {
  75.         perror(argv[1]);
  76.         exit(errno);
  77.     }
  78.     printf("address created\n");

  79.     /* 連接服務(wù)器 */
  80.     if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0) {
  81.         perror("Connect ");
  82.         exit(errno);
  83.     }
  84.     printf("server connected\n");

  85.     /* 基于 ctx 產(chǎn)生一個(gè)新的 SSL */
  86.     ssl = SSL_new(ctx);
  87.     SSL_set_fd(ssl, sockfd);
  88.     /* 建立 SSL 連接 */
  89.     if (SSL_connect(ssl) == -1)
  90.         ERR_print_errors_fp(stderr);
  91.     else {
  92.         printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
  93.         ShowCerts(ssl);
  94.     }

  95.     /* 接收對(duì)方發(fā)過(guò)來(lái)的消息,最多接收 MAXBUF 個(gè)字節(jié) */
  96.     bzero(buffer, MAXBUF + 1);
  97.     /* 接收服務(wù)器來(lái)的消息 */
  98.     len = SSL_read(ssl, buffer, MAXBUF);
  99.     if (len > 0)
  100.         printf("接收消息成功:'%s',共%d個(gè)字節(jié)的數(shù)據(jù)\n",
  101.                buffer, len);
  102.     else {
  103.         printf
  104.             ("消息接收失。″e(cuò)誤代碼是%d,錯(cuò)誤信息是'%s'\n",
  105.              errno, strerror(errno));
  106.         goto finish;
  107.     }
  108.     bzero(buffer, MAXBUF + 1);
  109.     strcpy(buffer, "from client->server");
  110.     /* 發(fā)消息給服務(wù)器 */
  111.     len = SSL_write(ssl, buffer, strlen(buffer));
  112.     if (len < 0)
  113.         printf
  114.             ("消息'%s'發(fā)送失敗!錯(cuò)誤代碼是%d,錯(cuò)誤信息是'%s'\n",
  115.              buffer, errno, strerror(errno));
  116.     else
  117.         printf("消息'%s'發(fā)送成功,共發(fā)送了%d個(gè)字節(jié)!\n",
  118.                buffer, len);

  119.   finish:
  120.     /* 關(guān)閉連接 */
  121.     SSL_shutdown(ssl);
  122.     SSL_free(ssl);
  123.     close(sockfd);
  124.     SSL_CTX_free(ctx);
  125.     return 0;
  126. }
復(fù)制代碼

編譯程序用下列命令:
gcc -Wall ssl-client.c -o client
gcc -Wall ssl-server.c -o server

運(yùn)行程序用如下命令:
./server 7838 1 cacert.pem privkey.pem
./client 127.0.0.1 7838

用下面這兩個(gè)命令產(chǎn)生上述cacert.pem和privkey.pem文件:
openssl genrsa -out privkey.pem 2048
openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095

具體請(qǐng)參考 “OpenSSL體系下使用密鑰數(shù)字證書(shū)等”

如果想對(duì)SSL有更深入的了解,請(qǐng)學(xué)習(xí)計(jì)算機(jī)安全相關(guān)的內(nèi)容,尤其是非對(duì)稱加密技術(shù)。
如果想對(duì)SSL庫(kù)的源代碼有深入學(xué)習(xí),請(qǐng)去 www.openssl.org 下載源碼來(lái)閱讀。

或者閱讀“SSL連接建立過(guò)程分析”其目錄和鏈接如下:

SSL連接建立過(guò)程分析(1)
1. 應(yīng)用程序接口
1.1 SSL初始化
1.2 建立SSL新連接
1.3 SSL通信
1.4 SSL釋放
2. SSL實(shí)現(xiàn)分析
2.1 SSL_load_error_strings
2.2 SSLeay_add_ssl_algorithms()
2.3 SSL23_server_method()
2.4 SSL23_client_method()
2.5 SSL_CTX_new ()
SSL連接建立過(guò)程分析(2)
2.6 SSL_CTX_set_default_passwd_cb[_userdata]()
2.7 SSL_CTX_use_certificate_file()
2.8 SSL_CTX_use_PrivateKey_file()
2.9 SSL_CTX_check_private_key()
2.10 SSL_new
2.11 SSL_set_fd
SSL連接建立過(guò)程分析(3)
2.12 SSL_accept
SSL連接建立過(guò)程分析(4)
2.13 SSL_connect
SSL連接建立過(guò)程分析(5)
2.14 SSL_read
SSL連接建立過(guò)程分析(6)
2.15 SSL_write

論壇徽章:
0
40 [報(bào)告]
發(fā)表于 2007-02-04 15:53 |只看該作者

Linux網(wǎng)絡(luò)編程一步一步學(xué)-select詳解

select系統(tǒng)調(diào)用是用來(lái)讓我們的程序監(jiān)視多個(gè)文件句柄(file descriptor)的狀態(tài)變化的。程序會(huì)停在select這里等待,直到被監(jiān)視的文件句柄有某一個(gè)或多個(gè)發(fā)生了狀態(tài)改變。

文件在句柄在Linux里很多,如果你man某個(gè)函數(shù),在函數(shù)返回值部分說(shuō)到成功后有一個(gè)文件句柄被創(chuàng)建的都是的,如man socket可以看到“On success, a file descriptor for the new socket is returned.”而man 2 open可以看到“open() and creat() return the new file descriptor”,其實(shí)文件句柄就是一個(gè)整數(shù),看socket函數(shù)的聲明就明白了:
int socket(int domain, int type, int protocol);

當(dāng)然,我們最熟悉的句柄是0、1、2三個(gè),0是標(biāo)準(zhǔn)輸入,1是標(biāo)準(zhǔn)輸出,2是標(biāo)準(zhǔn)錯(cuò)誤輸出。0、1、2是整數(shù)表示的,對(duì)應(yīng)的FILE *結(jié)構(gòu)的表示就是stdin、stdout、stderr,0就是stdin,1就是stdout,2就是stderr。
比如下面這兩段代碼都是從標(biāo)準(zhǔn)輸入讀入9個(gè)字節(jié)字符:

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <string.h>
  4. int main(int argc, char ** argv)
  5. {
  6.         char buf[10] = "";
  7.         read(0, buf, 9); /* 從標(biāo)準(zhǔn)輸入 0 讀入字符 */
  8.         fprintf(stdout, "%s\n", buf); /* 向標(biāo)準(zhǔn)輸出 stdout 寫(xiě)字符 */
  9.         return 0;
  10. }
復(fù)制代碼

/* **上面和下面的代碼都可以用來(lái)從標(biāo)準(zhǔn)輸入讀用戶輸入的9個(gè)字符** */

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <string.h>
  4. int main(int argc, char ** argv)
  5. {
  6.         char buf[10] = "";
  7.         fread(buf, 9, 1, stdin); /* 從標(biāo)準(zhǔn)輸入 stdin 讀入字符 */
  8.         write(1, buf, strlen(buf));
  9.         return 0;
  10. }
復(fù)制代碼

繼續(xù)上面說(shuō)的select,就是用來(lái)監(jiān)視某個(gè)或某些句柄的狀態(tài)變化的。select函數(shù)原型如下:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

函數(shù)的最后一個(gè)參數(shù)timeout顯然是一個(gè)超時(shí)時(shí)間值,其類型是struct timeval *,即一個(gè)struct timeval結(jié)構(gòu)的變量的指針,所以我們?cè)诔绦蚶镆昝饕粋(gè)struct timeval tv;然后把變量tv的地址&tv傳遞給select函數(shù)。struct timeval結(jié)構(gòu)如下:
struct timeval {
             long    tv_sec;         /* seconds */
             long    tv_usec;        /* microseconds */
         };

第2、3、4三個(gè)參數(shù)是一樣的類型: fd_set *,即我們?cè)诔绦蚶镆昝鲙讉(gè)fd_set類型的變量,比如rdfds, wtfds, exfds,然后把這個(gè)變量的地址&rdfds, &wtfds, &exfds 傳遞給select函數(shù)。這三個(gè)參數(shù)都是一個(gè)句柄的集合,第一個(gè)rdfds是用來(lái)保存這樣的句柄的:當(dāng)句柄的狀態(tài)變成可讀的時(shí)系統(tǒng)就會(huì)告訴select函數(shù)返回,同理第二個(gè)wtfds是指有句柄狀態(tài)變成可寫(xiě)的時(shí)系統(tǒng)就會(huì)告訴select函數(shù)返回,同理第三個(gè)參數(shù)exfds是特殊情況,即句柄上有特殊情況發(fā)生時(shí)系統(tǒng)會(huì)告訴select函數(shù)返回。特殊情況比如對(duì)方通過(guò)一個(gè)socket句柄發(fā)來(lái)了緊急數(shù)據(jù)。如果我們程序里只想檢測(cè)某個(gè)socket是否有數(shù)據(jù)可讀,我們可以這樣:
fd_set rdfds; /* 先申明一個(gè) fd_set 集合來(lái)保存我們要檢測(cè)的 socket句柄 */
struct timeval tv; /* 申明一個(gè)時(shí)間變量來(lái)保存時(shí)間 */
int ret; /* 保存返回值 */
FD_ZERO(&rdfds); /* 用select函數(shù)之前先把集合清零 */
FD_SET(socket, &rdfds); /* 把要檢測(cè)的句柄socket加入到集合里 */
tv.tv_sec = 1;
tv.tv_usec = 500; /* 設(shè)置select等待的最大時(shí)間為1秒加500毫秒 */
ret = select(socket + 1, &rdfds, NULL, NULL, &tv); /* 檢測(cè)我們上面設(shè)置到集合rdfds里的句柄是否有可讀信息 */
if(ret < 0) perror("select");/* 這說(shuō)明select函數(shù)出錯(cuò) */
else if(ret == 0) printf("超時(shí)\n"); /* 說(shuō)明在我們?cè)O(shè)定的時(shí)間值1秒加500毫秒的時(shí)間內(nèi),socket的狀態(tài)沒(méi)有發(fā)生變化 */
else { /* 說(shuō)明等待時(shí)間還未到1秒加500毫秒,socket的狀態(tài)發(fā)生了變化 */
    printf("ret=%d\n", ret); /* ret這個(gè)返回值記錄了發(fā)生狀態(tài)變化的句柄的數(shù)目,由于我們只監(jiān)視了socket這一個(gè)句柄,所以這里一定ret=1,如果同時(shí)有多個(gè)句柄發(fā)生變化返回的就是句柄的總和了 */
    /* 這里我們就應(yīng)該從socket這個(gè)句柄里讀取數(shù)據(jù)了,因?yàn)閟elect函數(shù)已經(jīng)告訴我們這個(gè)句柄里有數(shù)據(jù)可讀 */
    if(FD_ISSET(socket, &rdfds)) { /* 先判斷一下socket這外被監(jiān)視的句柄是否真的變成可讀的了 */
        /* 讀取socket句柄里的數(shù)據(jù) */
        recv(...);
    }
}

注意select函數(shù)的第一個(gè)參數(shù),是所有加入集合的句柄值的最大那個(gè)值還要加1。比如我們創(chuàng)建了3個(gè)句柄:
/************關(guān)于本文檔********************************************
*filename: Linux網(wǎng)絡(luò)編程一步一步學(xué)-select詳解
*purpose: 詳細(xì)說(shuō)明select的用法
*wrote by: zhoulifa(zhoulifa@163.com) 周立發(fā)(http://zhoulifa.bokee.com)
Linux愛(ài)好者 Linux知識(shí)傳播者 SOHO族 開(kāi)發(fā)者 最擅長(zhǎng)C語(yǔ)言
*date time:2007-02-03 19:40
*Note: 任何人可以任意復(fù)制代碼并運(yùn)用這些文檔,當(dāng)然包括你的商業(yè)用途
* 但請(qǐng)遵循GPL
*Thanks to:Google
*Hope:希望越來(lái)越多的人貢獻(xiàn)自己的力量,為科學(xué)技術(shù)發(fā)展出力
* 科技站在巨人的肩膀上進(jìn)步更快!感謝有開(kāi)源前輩的貢獻(xiàn)!
*********************************************************************/
int sa, sb, sc;
sa = socket(...); /* 分別創(chuàng)建3個(gè)句柄并連接到服務(wù)器上 */
connect(sa,...);
sb = socket(...);
connect(sb,...);
sc = socket(...);
connect(sc,...);

FD_SET(sa, &rdfds);/* 分別把3個(gè)句柄加入讀監(jiān)視集合里去 */
FD_SET(sb, &rdfds);
FD_SET(sc, &rdfds);

在使用select函數(shù)之前,一定要找到3個(gè)句柄中的最大值是哪個(gè),我們一般定義一個(gè)變量來(lái)保存最大值,取得最大socket值如下:
int maxfd = 0;
if(sa > maxfd) maxfd = sa;
if(sb > maxfd) maxfd = sb;
if(sc > maxfd) maxfd = sc;

然后調(diào)用select函數(shù):
ret = select(maxfd + 1, &rdfds, NULL, NULL, &tv); /* 注意是最大值還要加1 */

同樣的道理,如果我們要檢測(cè)用戶是否按了鍵盤(pán)進(jìn)行輸入,我們就應(yīng)該把標(biāo)準(zhǔn)輸入0這個(gè)句柄放到select里來(lái)檢測(cè),如下:
FD_ZERO(&rdfds);
FD_SET(0, &rdfds);
tv.tv_sec = 1;
tv.tv_usec = 0;
ret = select(1, &rdfds, NULL, NULL, &tv); /* 注意是最大值還要加1 */
if(ret < 0) perror("select");/* 出錯(cuò) */
else if(ret == 0) printf("超時(shí)\n"); /* 在我們?cè)O(shè)定的時(shí)間tv內(nèi),用戶沒(méi)有按鍵盤(pán) */
else { /* 用戶有按鍵盤(pán),要讀取用戶的輸入 */
    scanf("%s", buf);
}

詳細(xì)編程請(qǐng)參見(jiàn):
Linux網(wǎng)絡(luò)編程一步一步學(xué)-異步通訊聊天程序select
您需要登錄后才可以回帖 登錄 | 注冊(cè)

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號(hào)-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號(hào):11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國(guó)互聯(lián)網(wǎng)協(xié)會(huì)會(huì)員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過(guò)ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請(qǐng)注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP