一個簡單的socket網路程式設計
阿新 • • 發佈:2022-03-25
1 socket程式設計流程
1.1 建立socket
int socket(int domain, int type, int protocol);
domain 用於指定底層協議族,對 TCP/IP 協議族來說,應設定為 PF_INET(IPv4)或 PF_INET6(IPv6);type 用於指定服務型別,對 TCP/IP 族來說,SOCK_STREAM 表示使用 TCP 協議,SOCK_STREAM 表示使用 UDP 協議;protocol 是再選擇一個具體的協議,一般設為 0 使用預設協議即可。
1.2 命名socket
在服務端,需要呼叫 bind 將 socket 與 socket 地址進行繫結
int bind(int sockfd, const struct sockaddr* my_addr, socklen_t addrlen);
所有專用 socket 地址(比如 TCP/IP 協議族的 sockaddr_in 和 sockaddr_in6 等)在使用時都需要轉換為通用 socket 地址 sockaddr, 所以在傳入第二個引數時往往需要進行強制轉換。
1.3 監聽socket
呼叫 listen 指定被監聽的 socket 和監聽佇列的最大長度。
int listen(int sockfd, int backlog);
1.4 接受連線
int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen);
1.5 發起連線
客戶端通過 connect 與伺服器建立連線。
int connect(int sockfd, const struct sockaddr* serv_addr, socklen_t addrlen);
2 程式碼示例
2.1 服務端
#include<stdio.h> #include<stdlib.h> #include<assert.h> #include<string.h> #include<errno.h> #include<unistd.h> #include<sys/socket.h> #include<arpa/inet.h> const int BUFSIZE = 1024; int main(int argc, char* argv[]){ if(argc <= 3){ printf("usage: %s ip_adderss port number backlog\n", basename(argv[0])); return 1; } const char *ip = argv[1]; int port = atoi(argv[2]); //字串轉換整數 int backlog = atoi(argv[3]); /*建立socket*/ int sockfd = socket(PF_INET, SOCK_STREAM, 0); assert(sockfd >= 0); /*建立socket地址*/ 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 ret = bind(sockfd, (struct sockaddr*) &address, sizeof(address)); //繫結socket地址 assert(ret != -1); /*監聽socket*/ ret = listen(sockfd, backlog); assert(ret != -1); printf("Waiting for connection...\n"); struct sockaddr_in client; while(true){ socklen_t client_length = sizeof(client); /*accept連線*/ int connfd = accept(sockfd, (struct sockaddr *)&client, &client_length); if(connfd < 0){ printf("errno is: %d\n", errno); break; } printf("From client: IP is %s and Port is %d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port)); //輸出客戶端IP和埠 /*資料讀寫*/ char recv_buffer[BUFSIZE]; int n = recv(connfd, recv_buffer, BUFSIZE, 0); recv_buffer[n] = '\0'; printf("Got %d bytes of data: %s\n", n, recv_buffer); close(connfd); } close(sockfd); return 0; }
2.2 客戶端
#include<stdio.h> #include<stdlib.h> #include<assert.h> #include<string.h> #include<errno.h> #include<unistd.h> #include<sys/socket.h> #include<arpa/inet.h> const int BUFSIZE = 1024; int main(int argc, char* argv[]){ if(argc <= 2){ printf("usage: %s ip_adderss port number\n", basename(argv[0])); return 1; } const char *ip = argv[1]; int port = atoi(argv[2]); //字串轉換整數 /*建立socket*/ int sockfd = socket(PF_INET, SOCK_STREAM, 0); assert(sockfd >= 0); /*建立socket地址*/ 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); /*發起連線*/ if(connect(sockfd, (struct sockaddr *)&address, sizeof(address)) < 0){ printf("Connection failed\n"); exit(1); } /*資料讀寫*/ printf("Please enter information to the server:\n"); char send_buffer[BUFSIZE]; fgets(send_buffer, BUFSIZE, stdin); if(send(sockfd, send_buffer, strlen(send_buffer), 0) < 0){ printf("errno is: %d\n", errno); exit(1); } close(sockfd); return 0; }