struct sockaddr
and struct sockaddr_in
struct sockaddr
定義在<sys/socket.h>頭文件中,原型如下
/* Structure describing a generic socket address. */
struct sockaddr{
//unsigned short int sa_family;
//表明協議族,通常爲:AF_INET (IPV4) AF_INET6(IPV6)
//PF_INET含義同AF_INET一樣
__SOCKADDR_COMMON (sa_); /* Common data: address family and length. */
//存放ip地址的字符形式如:0.0.0.0
char sa_data[14]; /* Address data. */
};
struct sockaddr_in
定義在<netinet/in.h>中,原型如下:
/* Internet address. */
typedef uint32_t in_addr_t;
struct in_addr{
in_addr_t s_addr;
};
/* Structure describing an Internet socket address. */
struct sockaddr_in{
//short int sin_family;
__SOCKADDR_COMMON (sin_);
in_port_t sin_port; /* Port number. */
struct in_addr sin_addr; /* Internet address. */
/* Pad to size of `struct sockaddr'. */
unsigned char sin_zero[sizeof (struct sockaddr) -
__SOCKADDR_COMMON_SIZE -
sizeof (in_port_t) -
sizeof (struct in_addr)];
};
socket
函數
函數原型如下
/* Create a new socket of type TYPE in domain DOMAIN, using
protocol PROTOCOL. If PROTOCOL is zero, one is chosen automatically.
Returns a file descriptor for the new socket, or -1 for errors. */
extern int socket (int __domain, int __type, int __protocol) __THROW;
參數含義如下:
__domain 指明通信域,如 PF_UNIUX
(unix域)PF_INET
(IPV4) PF_INET6
(IPv6)
__type 指明通信類型,最常用SOCK_STREAM
(面向鏈接的可靠方式TCP),SOCK_DGRAM
(非面向鏈接的非可靠方式UDP),SOCK_STREAM
是數據流,一般都是TCP/IP協議的編程,SOCK_DGRAM
是數據包,是udp協議網絡編程
__protocol指定需要使用的協議,可以是:IPPROTO_TCP
和IPPROTO_UDP
使用0
則根據前兩個參數使用默認地址
NOTE
:創建成功則返回一個文件描述符,-1
則創建失敗
bind
函數
函數原型如下:
/* Give the socket FD the local address ADDR (which is LEN bytes long). */
extern int bind (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len)__THROW;
參數含義
__fd 調用scoket()
函數創建成功的文件描述符(file descriptor)
__addr 的類型其實是struct sockaddr *
一個本地地址
__len 第二個參數的大小
使用例子
struct sockaddr_in addr;
//創建socket,獲取一個socket描述符
if ((listen_fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
fprintf(stderr, "%s(): cannot create socket", __FUNCTION__);
return -1;
}
//設置server的地址同通信協議
memset(&addr, 0, sizeof(struct sockaddr_in));
//協議族: AF_INET AF_INET6 AF_LOCAL
addr.sin_family = AF_INET;
//取本地任意一個地址進行通信
// uint32_t htonl(uint32_t hostlong) 將主機無符號長整型轉化爲網絡字節
//INADDR_ANY=0.0.0.0
addr.sin_addr.s_addr = htonl(INADDR_ANY);
// uint16_t htons(uint16_t hostshort) 將hostshort 轉化爲網絡字節序
//網絡字節採用大端模式(big-ending),高位存放在低地址
addr.sin_port = htons(PORT);
if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) != 0) {
fprintf(stderr, "%s(): bind() failed", __FUNCTION__);
goto failed;
}
listen
函數
函數原型如下:
/* Prepare to accept connections on socket FD.
N connection requests will be queued before further requests are refused.
Returns 0 on success, -1 for errors. */
extern int listen (int __fd, int __n) __THROW;
參數含義
__fd 調用scoket()
函數創建成功的文件描述符(file descriptor)
__n 等待連接隊列的最大長度
NOTE
:返回0
代表成功 -1
代表失敗
accept
函數
函數原型如下:
/* Await a connection on socket FD.
When a connection arrives, open a new socket to communicate with it,
set *ADDR (which is *ADDR_LEN bytes long) to the address of the connecting
peer and *ADDR_LEN to the address's actual length, and return the
new socket's descriptor, or -1 for errors.
This function is a cancellation point and therefore not marked with
__THROW. */
extern int accept (int __fd, __SOCKADDR_ARG __addr,socklen_t *__restrict __addr_len);
參數含義:
__fd 調用scoket()
函數創建成功的文件描述符(file descriptor)
__addr 的類型其實是struct sockaddr *
鏈接成功會把客戶端的地址信息存入改結構體
__restrict __addr_len 第二個傳入的參數修改以後的實際大小
NOTE
:鏈接成功則返回一個文件描述符(以後的通信都使用它),-1
則創建失敗
connect
函數
函數原型如下:
/* Open a connection on socket FD to peer at ADDR (which LEN bytes long).
For connectionless socket types, just set the default address to send to
and the only address from which to accept transmissions.
Return 0 on success, -1 for errors.
This function is a cancellation point and therefore not marked with
__THROW. */
extern int connect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len);
參數含義:
__fd 客戶端調用scoket()
函數創建成功的文件描述符(file descriptor)
__addr 的類型其實是struct sockaddr *
需要建立鏈接的服務端的地址和端口信息(必須是網絡字節序)
__len 第二個參數結構體的大小
NOTE
:返回0
代表成功 -1
代表失敗
使用例子:
struct sockaddr_in clientAddr;
struct sockaddr_in serverAddr;
int socket_fd=-1;
bzero(&clientAddr, sizeof(clientAddr));
clientAddr.sin_family = AF_INET;
clientAddr.sin_addr.s_addr = htons(INADDR_ANY);
clientAddr.sin_port = htons(0);
//創建client
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (socket_fd < 0) {
fprintf(stderr, "initial tcp_client create socket failed\n");
return -1;
}
// 3.將socket建立爲非阻塞,此時socket被設置爲非阻塞模式
int flags = fcntl(socket_fd, F_GETFL, 0); //獲取建立的sockfd的當前狀態(非阻塞)
fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK); //將當前sockfd設置爲非阻塞
if (bind(socket_fd, (struct sockaddr *)&clientAddr, sizeof(clientAddr)) == -1) {
fprintf(stderr, "initial tcp_client bind socket failed\n");
return -1;
}
bzero(&serverAddr, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = inet_addr(tcp_server_ip);
serverAddr.sin_port = htons(tcp_server_port);
if(connect(socket_fd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == -1) {
fprintf(stderr, "connet to server failed\n");
return -1;
}