簡要概述
創建流程
服務端
- 創建一個套接字 ——socket()
- 綁定IP地址、端口等信息到socket上——bind()
- 監聽套接字——listen()
- 等待客戶端的連接請求——accept()
- 發送、接收數據——send()和recv(),或者read()和write()
- 關閉網絡連接——close()
客戶端
- 創建一個套接字——socket()
- 連接服務器——connect()
- 接收、發送數據——send()和recv(),或者read()和write()
- 關閉網絡連接——close()
代碼分析
實現服務器端向客戶端發送信息
以下socket編程用到的函數,可以點擊查看具體的socket常用函數解析
服務器端
一、創建一個套接字——socket()
//創建套接字
int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
二、綁定IP地址、端口等信息到socket上——bind()
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(1258); //端口
// 將套接字和IP、端口綁定
bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
三、監聽套接字——listen()
//進入監聽狀態,等待用戶發起請求
listen(serv_sock, 20);
四、等待客戶端的連接請求——accept()
//接收客戶端請求
struct sockaddr_in clnt_addr;
socklen_t clnt_addr_size = sizeof(clnt_addr);
int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
五、發送、接收數據——send()和recv(),或者read()和write()
//向客戶端發送數據
char str[] = "Hello World!";
write(clnt_sock, str, sizeof(str));
六、關閉網絡連接——close()
//關閉套接字
close(clnt_sock);
close(serv_sock);
客戶端
一、創建一個套接字——socket()
//創建套接字
int sock = socket(AF_INET, SOCK_STREAM, 0);
二、連接服務器——connect()
先設置要連接的服務器的IP地址和端口等屬性,然後連接
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
// 服務器端的信息
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(1258); //端口
//向服務器(特定的IP和端口)發起請求
connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
三、收發數據——send()和recv(),或者read()和write()
//讀取服務器傳回的數據
char buffer[40];
read(sock, buffer, sizeof(buffer)-1);
四、關閉網絡連接——close()
//關閉套接字
close(sock);
完整代碼
服務器端(service.c)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(){
//創建套接字
int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//將套接字和IP、端口綁定
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(1258); //端口
bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
//進入監聽狀態,等待用戶發起請求
listen(serv_sock, 20);
//接收客戶端請求
struct sockaddr_in clnt_addr;
socklen_t clnt_addr_size = sizeof(clnt_addr);
int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
//向客戶端發送數據
char str[] = "Hello World!";
write(clnt_sock, str, sizeof(str));
//關閉套接字
close(clnt_sock);
close(serv_sock);
return 0;
}
客戶端(client.c)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
int main(){
//創建套接字
int sock = socket(AF_INET, SOCK_STREAM, 0);
//向服務器(特定的IP和端口)發起請求
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(1258); //端口
connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
//讀取服務器傳回的數據
char buffer[40];
read(sock, buffer, sizeof(buffer)-1);
printf("Message form server: %s\n", buffer);
//關閉套接字
close(sock);
return 0;
}
運行
(需要開啓兩個終端)
先分別對兩個文件進行編譯(分別執行以下兩條命令)
gcc service.c -o service
gcc client.c -o client
然後先運行服務器端
./service
再在另一個終端中運行客戶端
./client
執行完成
此時服務器端運行結束
客戶端也運行結束,並打印出內容
Message form server: Hello World!
服務器端與客戶端是全雙工連接,即服務器端既可以發送數據也可以接收數據,客戶端亦如此