linux c 筆記 網路程式設計(二)

2022-09-03 14:00:25 字數 4875 閱讀 2031

套接字

struct sockaddr結構定義了一種通用的套接字位址,他在linux/socket.h中定義如下

struct sockaddr

;現在一般使用下面這個sockaddr_in結構(用來設定/獲取位址資訊):

struct sockaddr_in

;其中,in_addr這個資料結構:

struct sockaddr_in sock;

unsistruct sockaddr_in mysock;

sock.sin_family = af_inet;                  //tcp位址結構

sock.sin_port = htons(80);                 //設定埠號為80

sock.sin_addr.s_addr = inet_addr("202.205.3.195");    //設定ip位址

memset(sock.sin_zero ,0 , sizeof(sock.sin_zero));    //將陣列sin_zero清零

memset函式的原型為

memset(void * s ,int c ,size_t n);

一.建立套接字

#include

#include

int socket(int domain, int type, int protocol);

domain:用於指定建立套接字所使用的協議族,在標頭檔案中定義。有時候程式中會使用pf_inet,在標頭檔案中af_inet和pf_inet的數值是一致的。

常見的協議族如下:

af_unix:建立只在本機內進行通訊的套接字。    

af_inet:使用ipv4tcp/ip協議

af_inet6:使用ipv6 tcp/ip協議

說明:af_unix只能用於單一的unix系統程序間通訊,而af_inet是針對interne的,因而可以允許在遠端主機之間通訊。一般把它賦為af_inet。

type:指明套接子通訊的型別,對應的引數如下

sock_stream:建立tcp流套接字

sock_dgram:建立udp資料報套接字

sock_raw:建立原始套接字

protocol:指定某個協議的特定型別

引數protocol通常設定為0,表示通過引數domain指定的協議族和引數type指定的套接字型別來確定使用的協議。當為原始套接字時,系統無法唯一的確定協議,此時就需要使用使用該引數指定所使用的協議。

返回值:執行成功後返回乙個新建立的套接字;若有錯誤發生則返回乙個-1,錯誤**存入errno中。

下面用**建立乙個tcp套接字

int sock_fd;

sock_fd = socket(af_inet ,sock_stream ,0);

if(sock_fd < 0)

建立udp協議的套接字為

sock_fd = socket(af_inet ,sock_dgram ,0);

二.建立連線

函式connect用來在乙個指定的套接字上建立乙個連線,該函式原型

#include

#include

int connect (int socket ,const struct sockaddr *serv_addr ,socket_t addrlen);

sock_fd:建立套接字時返回的套接字檔案描述符,呼叫socket()返回的。

serv_addr:是乙個指向資料結構sockaddr的指標,其中包括客戶端需要連線的伺服器的目的ip位址和埠號。

addrlen:表示了第二了引數的大小,可以使用sizeof(struct sockaddr)

執行成功後返回0,有錯誤發生則返回-1,錯誤**存入errno中。

通常乙個面對連線的套接字(如tcp套接字)只能呼叫一次connect函式,而面對無連線的套接字(udp套接字)則可以多次呼叫connect函式以改變與目的位址的繫結

客戶端在建立套接字之後,不需要進行位址繫結,就可以直接連線伺服器。連線伺服器的函式為connect(),此函式連線指定引數的伺服器,例如ip位址,埠號。

如果是tcp程式設計,則connect()函式用於伺服器發出連線請求,伺服器的ip位址和埠號由 引數serv_addr指定。

如果是udp程式設計,則connect函式並不建立真正的連線,它只是告訴核心與該套接字進行通訊的目的位址(由第二個引數指定),只有該目的位址發來的資料才會被該socket接收。呼叫connect函式的好處是不必在每次傳送和接收資料時都指定目的位址。

該函式常見的用法如下

struct sockaddr_in  serv_addr;

memset (&serv_addr , 0 , sizeof(struct sockaddr_in) );     //將serv_addr的各個字段清零

serv_addr.sin_family =af_inet;

serv_addr.sin_port = htons(80);                //htons是位元組順序轉換函式,

// inet_aton函式將乙個字串轉換為乙個網路位址,並把該網路的位址賦給第二個引數

if(inet_aton("172.17.242.131", &serv_addr.sin_addr) < 0)

//使用sock_fd套接字連線到由serv_addr指定的位址上,假設sock_fd已定義

if(connect(sock_fd, (struct sockaddr *) &serv_addr ,sizeof(struct sockaddr_in )) <0 )

注意 serv_addr強制型別轉換為struct sockaddr型別

三.繫結套接字

函式bind()的作用是將乙個套接字檔案描述符與位址和埠繫結。

函式bind用來將乙個套接字和某個埠繫結在一起,函式的原型

#include

#include

int bind(int sockfd ,struct sockaddr *my_addr ,socklen_t addrlen );

sockfd:sockfd是呼叫socket函式返回的檔案描述符;

addrlen是sockaddr結構的長度。

my_addr: 是乙個指向sockaddr結構的指標,它儲存著本地套接字的位址(即埠和ip位址)資訊。

返回:成功返回0,失敗返回-1.

該函式的常用方法

struct sockaddr_in  serv_addr;

memset (&serv_addr ,0 , sizeof(struct sockaddr_in ));

serv_addr.sin_family = af_inef;

serv_addr.sin_port = htons(80);

serv_addr.sin_addr.s_addr = htonl(inaddr_any);

if( bind(sock_fd) ,(struct sockaddr *)&serv_addr ,sizeof(struct sockaddr_in ) < 0)

四.在套接字上監聽

函式listen 把套接字轉化為被動監聽,listen在套接字函式中表示讓乙個套接字處於監聽到來的連線請求的狀態,該函式原型

#include

int listen (int s , int backlog);

無錯誤,返回0,

否則,返回socket error,可以呼叫函式wsagetlasterror取得錯誤**。

listen函式使用主動連線套接字變為被連線套介面,使得乙個程序可以接受其它程序的請求,從而成為乙個伺服器程序。在tcp伺服器程式設計中listen函式把程序變為乙個伺服器,並指定相應的套接字變為被動連線。

listen函式一般在呼叫bind之後-呼叫accept之前呼叫。

該函式常見用法

#define listen_num  12     //定義連線請求佇列長度

....

if(listen (sock_fd , listen_num) < 0)

五.接受連線

函式accept用來接受乙個連線請求,該函式原型

#include

#include

int accept(int s ,struct sockaddr *addr ,socklen_t *addrlen);

引數s:由函式socket建立,經函式bind繫結到本地某一埠上,然後通過函式listen轉化而來的監聽套接字.

addr:用來儲存發起連線請求的主機的位址和埠

addrlen:是addr所指向的結構體的大小

執行成功返回乙個新的代表客戶端的套接字,出錯則返回-1,錯誤**存入errno中,詳細帶錯誤**手冊參考man手冊

返回值:accept()函式的返回值是新連線的客戶端套接字檔案描述符,與客戶端之間的通訊是通過accept()返回的新套接字檔案描述符來進行的,而不是通過建立套接字時的檔案描述符。如果accept()函式發生錯誤,accept()會返回-1,通過errno可以得到錯誤值。

如果引數sock_fd所指定的套接字被設定為阻塞方式(linux下的預設方式),且連線請求隊列為空,則accept()將被阻塞直到有連線請求到此為止;如果引數s所指定的套接字被設定為非阻塞方式,如果隊列為空,accept將立即返回-1,errno被設定為eagain.

套接字為阻塞方式下該函式的常見方法

int client_fd;

int client_len;

struct sockaddr_in  client_addr;

...client_len = sizeof(struct sockaddr_in);

client_fd = accept(sock_fd , (struct sockaddr *)&client_addr , &client_len );

if (conn_fd < 0)

linux c程式設計 網路程式設計

在網路上,通訊服務都是採用 c s機制,也就是客戶端 伺服器端工作流程 使用socket 函式建立伺服器端通訊套介面 使用bind 函式將建立的套介面與伺服器位址繫結 使用listen 函式使伺服器套介面做好接收連線請求準備 使用accept 接收來自客戶端由connect 函式發出的連線請求 根據...

Linux C程式設計(二)

1 父程序建立乙個新的文字檔案,並向文字檔案中寫入資料,當資料寫入完成後,用匿名管道通訊的方式將該檔案傳輸給子程序,同時用命名管道檔案將該檔案傳輸給另乙個程序 include include include include include include include define bufsz 2...

linux C語言網路程式設計學習總結《二》

3 建立連線 如果處理的是面向連線的網路服務 sock stream或sock seqpacket 在開始交換資料以前,需要在請求服務的程序套接字 客戶端 和提供服務的程序套接字 伺服器 之間建立乙個連線。用connect函式。include int connect int sockfd,const...