linux网络编程二:基础socket, bind, listen, accept, connect
?
linux網絡編程二:基礎socket, bind, listen, accept, connect
1. 創建socket
#include <sys/types.h> ? ?
#include <sys/socket.h>?
?
int socket(int domain, int type, int protocol); ?
?
(1)0domain參數為底層協議族:PF_INET(用于IPv4),PF_INET6(用于IPv6);對于UNIX本地域協議族為PF_UNIX。
(2)type參數指定服務類型:SOCK_STREAM(流服務,TCP協議),SOCK_UGRAM(數據報,UDP協議)。自linux2.6.17起,type參數可以接受上述服務與下面兩個重要的標志相與的值:SOCK_NONBLOCK和SOCK_CLOEXEC。它們分別表示新創建的socket設為非陰塞,以及在fork調用創建子進程時在子進程中關閉該socket。
(3)protocol參數是在前兩個參數構成的協議集合下,再選擇一個具體的協議。不過這個值通常都是唯一的(前兩個值已經完全決定了它的值)。幾乎在所有情況下都設置為0, 表示使用默認協議。調用成功返回一個socket文件描述符,失敗返回-1,并設置errno。
2. 命名socket
#include <sys/types.h> ??
#include <sys/socket.h> ? ?
int bind(int socket, const struct sockaddr* my_addr, socklen_t addrlen);?
?
bind將my_addr所指的socket地址分配給未命名的sockfd文件描述符,addrlen參數指出該socket地址的長度。
調用成功返回0, 失敗返回-1,并設置errno。
3. 監聽socket
#include <sys/socket.h> ??
int listen(int sockfd, int backlog); ?
創建一個監聽隊列以存放待處理的客戶連接。sockfd參數指定被 監聽的socket。backlog參數提示內核監聽隊列的最大長度。如果監聽隊列的長度超過backlog,服務器將不受理新的客戶連接,客戶端也將收到ECONNREFUSED錯誤信息。在內核版本2.2之前,backlog是指所有處于半連接狀態(SYN_RCVD)和完全連接狀態(ESTABLISHED)的socket上限。但在內核版本2.2以后, 它只表示處于完全連接狀態的socket上限,處于半連接狀態的socket上限則由/proc/sys/net/ipv4/tcp_max_syn_backlog內核參數定義。
backlog參數的典型值為5。調用成功時返為0, 失敗時為-1, 并設置errno。
4. 接受連接,從listen監聽隊列中接受一個連接
#include <sys/types.h> ??
#include <sys/socket.h> ? ?
int accept(int sockfd, struct sockaddr* addr, socklen_t *addrlen); ?
sockfd參數是執行過listen調用的監聽socket。addr參數用來獲取被接受連接的遠端socket地址,該地址的長度由addrlen參數指出。調用成功時返回一個新的連接socket,該socket唯一標識了被接受的這個連接,服務器可通過讀寫該socket來與客戶端通信; 失敗時返回-1,并設置errno。
5. ?客戶端發起連接
#include <sys/types.h> ??
#include <sys/socket.h> ??
int connect(int sockfd, const struct sockaddr* serv_addr, socklen_t addrlen); ?
sockfd參數由socket系統調用返回一個socket。
serv_addr參數是服務器監聽的socket地址。addrlen參數指定serv_addr的長度。
?
調用成功返回0, 一旦成功建立連接,sockfd就唯一標識了這個連接,客戶端就可以通過讀寫sockfd來與服務器通信。 失敗返回-1, 并設置errno。常見兩種 errno是 ECONNREFUSED(目標端口不存在,連接被拒絕) 和 ETIMEDOUT(連接超時)。
?
?
#include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <assert.h> #include <unistd.h> #include <stdlib.h> #include <errno.h> #include <string.h> int main(int argc, char **argv) { if (argc <= 2) { fprintf(stderr, "Usage: %s ip port\n", basename(argv[0])); return 1; } const char *ip = argv[1]; int port = atoi(argv[2]); struct sockaddr_in address; bzero(&address, sizeof(address)); address.sin_family = AF_INET; address.sin_port = htons(port); inet_pton(AF_INET, ip, &address.sin_addr); int sock = socket(PF_INET, SOCK_STREAM, 0); assert(sock >= 0); int ret = bind(sock, (struct sockaddr*)&address, sizeof(address)); assert(ret != -1); ret = listen(sock, 5); assert(ret != -1); struct sockaddr_in client; socklen_t client_addrlength = sizeof(client); int connfd = accept(sock, (struct sockaddr*)&client, &client_addrlength); if(connfd < 0) { fprintf(stderr, "errno is: %s\n", strerror(errno)); } else { char remote[INET_ADDRSTRLEN]; fprintf(stderr, "connected with ip:%s and port:%d\n", inet_ntop(AF_INET,&client.sin_addr,remote, INET_ADDRSTRLEN), ntohs(client.sin_port)); close(connfd); } close(sock); return 0; }?
?
?
?
?
總結
以上是生活随笔為你收集整理的linux网络编程二:基础socket, bind, listen, accept, connect的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux网络编程一:主机字节序与网络字
- 下一篇: Qt中的槽