套接字
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...