基于Linux下C語言的Socket網(wǎng)絡(luò)編程

基于Linux下C語言的Socket網(wǎng)絡(luò)編程


網(wǎng)絡(luò)上的兩個程序通過一個雙向的通信連接實現(xiàn)數(shù)據(jù)的交換,這個連接的一端稱為一個socket狐蜕。

Socket被廣泛用作網(wǎng)絡(luò)通信,它幾乎支持所有的編程語言芭商,各種語言對于Socket操作流程也比較類似语盈。
服務(wù)端程序的創(chuàng)建流程為創(chuàng)建socket——綁定端口號——監(jiān)聽——接受連接——讀和寫哑了;
客戶端程序的創(chuàng)建流程為創(chuàng)建socket——通過IP和端口連接服務(wù)端——讀和寫。
[TOC]

服務(wù)端

1. 創(chuàng)建Socket

包含頭文件:
#include <sys/socket.h>
#include <sys/types.h>
函數(shù)原型:int socket(int domain, int type, int protocol);
socket函數(shù)里有三個參數(shù)烧颖。
domain選擇通信協(xié)議族弱左,常用的有以下幾種。

Name Purpose
AF_UNIX, AF_LOCAL Local communication
AF_INET(常用) IPv4 Internet protocols
AF_INET6 IPv6 Internet protocols

type指定Socket類型炕淮,常用以下幾種拆火。

Name Purpose
SOCK_STREAM 流式套接字(TCP協(xié)議)
SOCK_DGRAM 數(shù)據(jù)報式套接字(UDP協(xié)議)

protocol指定協(xié)議,常用以下幾種

NAME Purpose
IPPROTO_TCP TCP傳輸協(xié)議
IPPROTO_UDP UDP傳輸協(xié)議
IPPROTO_STCP STCP傳輸協(xié)議
IPPROTO_TIPC TIPC傳輸協(xié)議

type和protocol不可以隨意組合涂圆,當?shù)谌齻€參數(shù)type0自動選擇第二個參數(shù)對應(yīng)的默認協(xié)議

Socket如果創(chuàng)建成功们镜,則返回一個描述該網(wǎng)絡(luò)通信端點的文件描述符,操作系統(tǒng)會自動分配當前最小可用的文件描述符润歉。
示例代碼
int sockfd = socket(AF_INET, SOCK_STREAM, 0);

2. 綁定端口號和IP地址

包含頭文件:
#include <sys/socket.h>
#include <sys/types.h>
函數(shù)原型:int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
bind()函數(shù)把地址族中的特定地址賦給socket模狭。
sockfdsocket描述字,通過socket創(chuàng)建踩衩,標識唯一一個服務(wù)端描述字嚼鹉。
sockaddr結(jié)構(gòu)體,通過初始化sockaddr_in結(jié)構(gòu)體然后進行強制類型轉(zhuǎn)化九妈。示例代碼如下:

struct sockaddr_in *server_socket = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
memset(server_socket, 0, sizeof (struct sockaddr_in)); // 清空sockaddr_in 結(jié)構(gòu)體
server_socket->sin_addr.s_addr = htonl(INADDR_ANY); // 任意IP地址
server_socket->sin_family = AF_INET; // 使用IPv4協(xié)議族
server_socket->sin_port = htons(PORT); // 端口號

addrlensockaddr的長度反砌。
bind示例代碼如下
bind(sockfd, (struct sockaddr *)server_socket, sizeof (struct sockaddr));

3. 連接和監(jiān)聽

包含頭文件:
#include <sys/socket.h>
#include <sys/types.h>
函數(shù)原型int listen(int sockfd, int backlog);
sockfd為服務(wù)端建立socket的文件描述符
backlog為對應(yīng)socket可以排隊的最大連接數(shù)
服務(wù)端調(diào)用listen()函數(shù)監(jiān)聽socket,當客戶端通過connect()函數(shù)連接服務(wù)端萌朱,發(fā)送連接請求時宴树,listen()就會監(jiān)聽到這個請求。

4. 接受客戶端連接

包含頭文件:
#include <sys/socket.h>
#include <sys/types.h>
函數(shù)原型int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
sockfd為服務(wù)端打開的socket描述字
addr用于保存連接的客戶端的IP地址和端口號晶疼,其內(nèi)容與sockaddr結(jié)構(gòu)體類似酒贬。
addrlen是接受地址的長度。
accept()函數(shù)如果執(zhí)行成功翠霍,則返回一個由內(nèi)核生成的全新的套接字锭吨,用于和新客戶端之間通信。

5. 讀和寫

包含頭文件:
#include <unistd.h>
函數(shù)原型:ssize_t read(int fd, void *buf, size_t count);
函數(shù)原型:ssize_t write(int fd, const void *buf, size_t count);
當socket打開網(wǎng)絡(luò)描述字后寒匙,程序可以像讀寫文件一樣向網(wǎng)絡(luò)描述字讀或者寫零如,對應(yīng)接受和發(fā)送數(shù)據(jù)。

客戶端

1. 創(chuàng)建socket

過程同服務(wù)端锄弱,socket返回的套接字描述符將直接用于和對端通信考蕾。

2. 連接服務(wù)器

函數(shù)原型int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockfd為客戶端建立socket的文件描述符
addr為sockaddr結(jié)構(gòu)體保存的服務(wù)端的IP地址和端口號,以及協(xié)議類型会宪,例如:

struct sockaddr_in *server_addr = (struct sockaddr_in *)malloc(sizeof (struct sockaddr_in)); 
memset(server_addr, 0, sizeof (struct sockaddr_in)); 
server_addr->sin_family = AF_INET; // 使用IPv4協(xié)議族
server_addr->sin_port = htons(port); // port為服務(wù)器綁定的端口號
inet_pton(AF_INET, "xxx.xxx.xxx.xxx", &server_addr->sin_addr); // 服務(wù)端的IP地址

客戶端發(fā)起tcp連接請求肖卧,服務(wù)端監(jiān)聽到請求并接受請求后,TCP連接建立即可以開始傳輸文件掸鹅。(如果使用UDP協(xié)議有些許區(qū)別塞帐,暫時不做討論拦赠。)

3.發(fā)送數(shù)據(jù)

連接建立后,客戶端通過write()write()函數(shù)向打開的sockfd發(fā)送或接受數(shù)據(jù)

代碼示例

Server

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define PORT 8000

int main()
{
    // 創(chuàng)建socket 
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    // 申請服務(wù)端和客戶端地址結(jié)構(gòu)體空間葵姥,客戶端地址用于保存新連接的地址端口信息
    struct sockaddr_in *server_socket = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
    struct sockaddr_in *client_socket = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
    socklen_t client_address_len;
    memset(server_socket, 0, sizeof (struct sockaddr_in));
    memset(client_socket, 0, sizeof (struct sockaddr_in));
    server_socket->sin_addr.s_addr = htonl(INADDR_ANY);
    server_socket->sin_family = AF_INET;
    server_socket->sin_port = htons(PORT);
    // 綁定
    bind(sockfd, (struct sockaddr *)server_socket, sizeof (struct sockaddr));
    // 監(jiān)聽
    listen(sockfd, 20);
    // 接受
    int connect_fd = accept(sockfd, (struct sockaddr *)client_socket, &client_address_len);
    char buf[] = "Hello Wrold!";
    // 發(fā)送
    while(write(connect_fd, buf, strlen(buf)))
    {
        printf("send msg: %s\n", buf);
        sleep(1);
    }
    return 0;
}

Client

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    // 創(chuàng)建socket
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    // 準備地址結(jié)構(gòu)體
    struct sockaddr_in *server_addr = (struct sockaddr_in *)malloc(sizeof (struct sockaddr_in));
    memset(server_addr, 0, sizeof (struct sockaddr_in));
    server_addr->sin_family = AF_INET;
    server_addr->sin_port = htons(8000);
    inet_pton(AF_INET, "127.0.0.1", &server_addr->sin_addr);
    // 連接
    connect(sockfd, (struct sockaddr *)server_addr, sizeof (struct sockaddr)); // sockaddr_in強制轉(zhuǎn)換成sockaddr
    char buf[1024] = "";
    // 讀取
    while(read(sockfd, buf, 1024))
    {
        printf("recv msg: %s\n", buf);
        memset(buf, 0, 1024);
    }
    return 0;
}


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末荷鼠,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子牌里,更是在濱河造成了極大的恐慌颊咬,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件牡辽,死亡現(xiàn)場離奇詭異,居然都是意外死亡敞临,警方通過查閱死者的電腦和手機态辛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來挺尿,“玉大人奏黑,你說我怎么就攤上這事”喾” “怎么了熟史?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長窄俏。 經(jīng)常有香客問我蹂匹,道長,這世上最難降的妖魔是什么凹蜈? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任限寞,我火速辦了婚禮,結(jié)果婚禮上仰坦,老公的妹妹穿的比我還像新娘履植。我一直安慰自己,他們只是感情好悄晃,可當我...
    茶點故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布玫霎。 她就那樣靜靜地躺著,像睡著了一般妈橄。 火紅的嫁衣襯著肌膚如雪庶近。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天眷细,我揣著相機與錄音拦盹,去河邊找鬼。 笑死溪椎,一個胖子當著我的面吹牛普舆,可吹牛的內(nèi)容都是我干的恬口。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼沼侣,長吁一口氣:“原來是場噩夢啊……” “哼祖能!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蛾洛,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤养铸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后轧膘,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钞螟,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年谎碍,在試婚紗的時候發(fā)現(xiàn)自己被綠了鳞滨。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,654評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡蟆淀,死狀恐怖拯啦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情熔任,我是刑警寧澤褒链,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站疑苔,受9級特大地震影響甫匹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜夯巷,卻給世界環(huán)境...
    茶點故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一赛惩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧趁餐,春花似錦喷兼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至臀突,卻和暖如春勉抓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背候学。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工藕筋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人梳码。 一個月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓隐圾,卻偏偏與公主長得像伍掀,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子暇藏,可洞房花燭夜當晚...
    茶點故事閱讀 43,543評論 2 349

推薦閱讀更多精彩內(nèi)容