【Linux Socket編程】——簡述常用的Socket編程函數

操作系統:Linux

主要簡述:Socket編程常用函數

編程語言:c語言

本文涉及到的函數有

socket()、bind()、connect()、listen()、accept()、send()、recv()

涉及到的結構體有

sockaddr_in、in_addr、sockaddr

socket()函數

創建套接字

頭文件

#include <sys/socket.h>

函數原型

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

af:IP地址的類型

  • AF_INET : IPv4
  • AF_INET6: IPV6

type:數據傳輸方式

  • SOCK_STREAM:面向連接的數據傳輸方式
  • SOCK_DGRAM:無連接的數據傳輸方式

protocol:傳輸協議

  • IPPROTO_TCP:TCP傳輸協議
  • IPPTOTO_UDP:UDP傳輸協議

返回值

  • 成功:0
  • 失敗:-1

舉例

使用IPv4協議、面向連接的數據傳輸方式、TCP傳輸協議,來創建套接字

int tcp_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

一般情況下有了 af 和 type 兩個參數就可以創建套接字了,操作系統會自動推演出協議類型

所以上述例子也可以寫出以下形式(將傳輸協議設爲0)

int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);

 

bind()函數

地址綁定,將套接字與地址關聯

頭文件

#include <sys/types.h> 
#include <sys/socket.h>

函數原型

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

sockfd:socket文件描述符

addr:sockaddr 結構體變量的指針

addrlen:addr 變量的大小

返回值

  • 成功:0
  • 失敗:-1

舉例

//創建套接字 
int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
//創建sockaddr_in結構體變量 
struct sockaddr_in serv_addr; 
memset(&serv_addr, 0, sizeof(serv_addr)); //每個字節都用0填充 
serv_addr.sin_family = AF_INET; //使用IPv4地址 
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具體的IP地址 
serv_addr.sin_port = htons(1234); //端口 
//將套接字和IP、端口綁定 
bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

sockaddr_in 結構體

struct sockaddr_in{ 
    sa_family_t sin_family; //地址族,也就是地址類型 
    uint16_t sin_port; //16位的端口號 
    struct in_addr sin_addr; //32位IP地址 
    char sin_zero[8]; //不使用,一般用0填充 
};

端口號需要用 htons() 函數轉換


in_addr 結構體

頭文件

#include <netinet/in.h> 

結構體

struct in_addr{ 
    in_addr_t s_addr; //32位的IP地址 
};

sockaddr 結構體

struct sockaddr{ 
    sa_family_t sin_family; //地址族,也就是地址類型 
    char sa_data[14]; //IP地址和端口號 
};

sockaddr 是一種通用的結構體,可以用來保存多種類型的IP地址和端口號,而 sockaddr_in 是專門用來保存 IPv4 地址的結構體

 

connect() 函數

建立連接,創建與指定外部端口的連接

頭文件

#include <sys/types.h> 
#include <sys/socket.h>

函數原型

int connect(int sockfd, struct sockaddr *serv_addr, socklen_t addrlen);

sockfd:socket文件描述符

addr:sockaddr 結構體變量的指針

addrlen:addr 變量的大小

返回值

  • 成功:0
  • 失敗:-1

舉例

connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) 

 

listen() 函數

讓套接字進入被動監聽狀態

使得一個進程可以接受其它進程的請求,從而成爲一個服務器進程

  • 被動監聽:指當沒有客戶端請求時,套接字處於“睡眠”狀態,只有當接收到客戶端請求時,套接字纔會被“喚醒”來響應請求

頭文件

#include <sys/types.h> 
#include <sys/socket.h>

函數原型

int listen(int sockfd, int backlog);

sockfd:被監聽的套接字的標識符

backlog:請求隊列的最大長度(能存放多少個客戶端請求)

  • 請求隊列:當套接字正在處理客戶端請求時,如果有新的請求進來,套接字將把新的請求放入緩衝區,再從緩衝區取出請求 ,此緩衝區稱爲請求隊列

返回值

  • 成功:0
  • 失敗:-1

舉例

#define BACKLOG 10 
... 
if (listen(sockfd, BACKLOG) == -1) { 
    perror("listen出錯!"); 
    exit(1); 
}

 

accept() 函數

在一個套接口接受一個連接,當套接字處於監聽狀態時,可以通過 accept() 函數來接收客戶端請求

accept() 會阻塞程序執行(後面代碼不能被執行),直到有新的請求到來

頭文件

#include<sys/socket.h>

函數原型

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

sockfd:服務器端套接字的標識符

addr:sockaddr 結構體變量的指針

addrlen:addr 變量的大小

返回值

  • 成功:返回接收到的套接字的描述符
  • 失敗:-1

舉例

struct sockaddr_in cli_addr; 
sin_size = sizeof(cli_addr); 
accept(sockfd, (struct sockaddr *)&cli_addr, &sin_size));

 

send()函數

發送數據

將數據由指定的socket 傳給對方主機

頭文件

#include <sys/types.h> 
#include <sys/socket.h>

函數原型

int send(int s, const void * msg, int len, unsigned int falgs);

s:以建立好連接的socket標識符

msg:發送的消息內容

len:發送內容的長度

falgs:一般設爲0

返回值

  • 成功:返回實際傳送出去的字符數
  • 失敗:-1

舉例

client_fd = accept(sockfd, (struct sockaddr *)&remote_addr, &sin_size));
... 
send(client_fd, "Hello, this is a message\n", 26, 0);

 

recv()函數

接收數據

接收遠端主機經指定的 socket 傳來的數據, 並把數據存到 buf 指向的內存空間

頭文件

#include <sys/types.h> 
#include <sys/socket.h>

函數原型

int recv(int sock, void *buf, int len, unsigned int flags);

sock:接收端套接字描述符

buf:指定緩衝區,存放接收到的數據

len:緩衝區的長度

flags:一般設爲0

返回值

  • 成功:返回接收到的字符數
  • 失敗:-1

舉例

#define MAXDATASIZE 100 /*每次最大數據傳輸量 */ 
recv(sockfd, buf, MAXDATASIZE, 0))

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章