1. 程式人生 > >socket API和TCP/IP協議學習

socket API和TCP/IP協議學習

socket API和TCP/IP協議學習


  • 本部落格用於記錄socket API和TCP/IP協議的學習
  • 目標在2017.1.1之前看完unix網路程式設計卷一和TCP/IP詳解卷一
  • 本部落格的環境是opensuse Tumbleweed,其他linux發行版可能會有差異

首先放上簡單的server/client程式碼

這兩段程式碼展示了socket連線的一般步驟

  • 注意:這個程式碼缺少了相關的標頭檔案,不能直接跑哦!
  • 部落格對應完整程式碼見我的github

server.c

#include <stdio.h>
#include <netinet/in.h> #include <string.h> #include <time.h> #include <zconf.h> #include <stdlib.h> #include "../unp_prac.h" /** * 這是server端的程式,流程總結為: * 1.函式socket返回listenfd * 2.設定servaddr(先使用bzero); * 3.bind,繫結seraddr和listenfd * 4.listen,將套接字轉換成監聽套接字。 * ---以上socket bind listen 是任何TCP伺服器準備監聽描述符的正常步驟 * 5.無窮迴圈for(;;) * 6.呼叫accept(等待某個連線到達並被核心接受), * 在accept中,TCP連線使用所謂的三路握手建立連線,完畢則返回已連線描述符(confd),用於與客戶程序通訊。 * 7.關閉confd,終止連線。 */
/** * 編譯: * gcc -o server server.c ../lib_io/writen.c ../lib/error.c */ int main(int argc, char **argv) { int listenfd, confd; struct sockaddr_in servaddr; char buff[MAXLINE]; time_t ticks; //socket函式建立一個網際(AF_INET)位元組流(SOCK_STREAM)套接字,這是TCP套接字的花哨名字。 //返回一個小整數的描述符。 if ((listenfd = socket(AF_INET, SOCK_STREAM, 0
)) < 0) { printf("呼叫socket函式失敗"); } //設定伺服器 //將servaddr記憶體區域清0; bzero(&servaddr, sizeof servaddr); //設定seraddr servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//設為any:如果伺服器有多個網路介面,那麼伺服器程序可以在所有介面上接受使用者連線 servaddr.sin_port = htons(port);/*時間服務的埠為13*/ //bind if ((bind(listenfd, (SA *) &servaddr, sizeof(servaddr))) < 0) { printf("\033[31mbind失敗,埠未被系統釋放\n請修改unp_prac.h中的port,然後clean,重新編譯執行\n\033[0m"); exit(0); }; //listen listen(listenfd, LISTENQ); printf("建立監聽連線符,等待連線\n"); while (1) { confd = accept(listenfd, (SA *) NULL, NULL); printf("接受連線,返回時間\n"); ticks = time(NULL); snprintf(buff, sizeof(buff), "\033[35m%.24s\n\033[0m", ctime(&ticks)); Writen(confd, buff, strlen(buff)); close(confd); } return 0; }

client.c

#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <zconf.h>
#include "../unp_prac.h"
#include "../lib/inet_pton.h"




/**
 * 這是客戶端的程式碼,步驟為下
 * 1.socket返回socket描述符
 * 2.設定seraddr
 * 3.connect
 * 4.read socket描述符
 */

/**
 * 編譯
 * gcc -o client client.c ../lib_io/readn.c ../lib/error.c 
 */

int main(int argc, char **argv) {
    int sockfd, n;
    char recvline[MAXLINE + 1];
    struct sockaddr_in servaddr;
    char *servIP;

    if (argc != 2) {
        servIP = "127.0.0.1";
    } else {
        servIP = argv[0];
    }

    //socket函式建立一個網ji(AF_INET)位元組流(SOCK_STREAM)套接字,這是TCP套接字的花哨名字。
    //返回一個小整數的描述符。
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("呼叫socket函式失敗");
    }


    //首先清空servaddr結構體,作用等同於memset
    //書上推薦使用bzero是因為只有兩個引數,比較好記
    bzero(&servaddr, sizeof servaddr);
    servaddr.sin_family = AF_INET;//置地址族為AF_INET
    servaddr.sin_port = htons(port);//htons函式負責將整數轉換成二進位制埠號
    if ((inet_pton(AF_INET, servIP, &servaddr.sin_addr)) < 0) {
        printf("轉換失敗");
    }//將ASCII命令列引數轉化為正確的形式

    if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0) {
        printf("連線失敗\n");
    };

    while ((n = Readn(sockfd, recvline, MAXLINE)) > 0) {
        recvline[n] = 0;
        if (fputs(recvline, stdout) == EOF) {
            printf("寫到標準輸出失敗\n");
        }
    }
    if (n < 0) {
        printf("讀取失敗\n");
    }
}

相關文章

1.套接字程式設計基礎
2.基本套接字函式