socket编程的常用函数,可以参考以下这篇博客
socket编程-----常用socket编程函数https://blog.csdn.net/ZZZCY2003/article/details/138071210
关于TCP的三次挥手、四次挥手过程和UDP的报文分析可以参考以下两篇博客
计算机网络--运输层https://blog.csdn.net/ZZZCY2003/article/details/138007052
TCP协议数据传输过程及报文分析https://blog.csdn.net/ZZZCY2003/article/details/138035752
目录
一、socket
1.1、socket概述
1.2、基本概念
1.3、关键步骤
1.4、在Linux系统上执行socket过程
二、基于socket编程的TCP通信过程
2.1、基于socket编程的TCP通信流程
2.1.1、服务端(service.c)
2.1.1.1、创建socket
2.1.1.2、绑定socket到端口
2.1.1.3、开始监听连接
2.1.1.4、接受客户端连接
2.1.1.5、读取客户端发送的数据
2.1.1.6、发送响应给客户端
2.1.1.7、关闭套接字
2.1.2、客户端(client.c)
2.1.2.1、创建socket
2.1.2.2、设置服务器地址结构并来连接服务器
2.1.2.3、发送数据给服务器
2.1.2.4、读取服务器的响应
2.1.2.5、关闭套接字
2.2、基于socket编程的TCP通信流程图
2.3、基于socket编程的TCP示例
2.3.1、服务端(service.c)
2.3.2、客户端(client.c)
三、基于socket编程的UDP通信过程
3.1、基于socket编程的UDP通信流程
3.1.1、服务端
3.1.1.1、创建socket
3.1.1.2、设置服务器地址结构
3.1.1.3、绑定socket
3.1.1.4、打印监听信息
3.1.1.5、接收数据
3.1.1.6、关闭socket
3.1.2、客户端
3.1.2.1、创建socket
3.1.2.2、设置服务器地址结构
3.1.2.3、发送数据
3.1.2.4、打印发送信息
3.1.2.5、关闭socket
3.2、基于socket编程的UDP通信流程图
3.3、基于socket编程的UDP通信示例
3.3.1、服务端(service.c)
3.3.2、客户端(client.c)
一、socket
1.1、socket概述
Socket编程是计算机网络通信中的一种重要技术,它允许不同的计算机程序通过网络进行通信和数据交换。在Socket编程中,一个程序(通常称为客户端)通过创建Socket对象并与另一个程序(通常称为服务器)建立连接,从而进行通信。
1.2、基本概念
-
IP地址和端口号:IP地址用于标识网络上的设备,而端口号用于标识设备上的特定服务或应用程序。Socket通过组合IP地址和端口号来唯一标识一个网络上的通信端点。
-
客户端与服务器:在Socket编程中,通常有一个服务器程序等待客户端的连接请求。一旦连接建立,客户端和服务器就可以互相发送和接收数据。
-
流式套接字(SOCK_STREAM):通常用于TCP协议,提供可靠的、面向连接的通信服务。数据按照字节流的形式发送和接收。
-
数据报套接字(SOCK_DGRAM):通常用于UDP协议,提供无连接的通信服务。数据以数据报的形式发送和接收,不保证数据的顺序和可靠性。
1.3、关键步骤
-
创建Socket:使用socket函数创建一个新的Socket对象。
-
绑定(Bind):对于服务器来说,需要将Socket绑定到一个特定的IP地址和端口号上,以便客户端能够连接。
-
监听(Listen):服务器Socket使用listen函数开始监听来自客户端的连接请求。
-
接受连接(Accept):服务器使用accept函数接受客户端的连接请求,并返回一个新的Socket对象用于与客户端通信。
-
连接(Connect):对于客户端来说,使用connect函数向服务器发起连接请求。
-
发送和接收数据:使用send或sendto函数发送数据,使用recv或recvfrom函数接收数据。
-
关闭Socket:使用close函数关闭Socket连接,释放资源。
1.4、在Linux系统上执行socket过程
假设已经写好服务端代码(service.c)和客户端代码(client.c)(注意:示例用的是C语言代码和python代码,且代码已附在文章最下面)
1、开启两个终端,并对服务端代码和客户端代码进行编译。在两个终端中分别执行以下各一条代码,作为服务端和客户端。
gcc service.c -o service
gcc client.c -o client
2、运行服务端,使服务端处于等待连接状态。等待客户端的请求连接。
./service
3、在另一个终端运行客户端,向服务端发出请求连接的请求
./client
4、最后,执行完成!
二、基于socket编程的TCP通信过程
2.1、基于socket编程的TCP通信流程
2.1.1、服务端(service.c)
2.1.1.1、创建socket
//创建socket文件描述符
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
2.1.1.2、绑定socket到端口
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("127.0.0.1");
address.sin_port = htons(PORT);
//绑定socket到端口
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
2.1.1.3、开始监听连接
//开始监听连接
if (listen(server_fd, 3) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
2.1.1.4、接受客户端连接
//接受客户端连接
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
2.1.1.5、读取客户端发送的数据
//读取客户端发送的数据
int valread = read(new_socket, buffer, BUFFER_SIZE);
printf("%s\n", buffer);
2.1.1.6、发送响应给客户端
//发送响应给客户端
send(new_socket, hello, strlen(hello), 0);
printf("Hello message sent\n");
2.1.1.7、关闭套接字
//关闭套接字
close(server_fd);
close(new_socket);
2.1.2、客户端(client.c)
2.1.2.1、创建socket
//创建socket文件描述符
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("Socket creation error");
exit(EXIT_FAILURE);
}
2.1.2.2、设置服务器地址结构并来连接服务器
//设置服务器地址结构
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
//连接到服务器
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
perror("Connection failed");
exit(EXIT_FAILURE);
}
printf("Connected to server\n");
2.1.2.3、发送数据给服务器
//发送数据给服务器
if (send(sock, hello, strlen(hello), 0) < 0) {
perror("Send failed");
exit(EXIT_FAILURE);
}
printf("Hello message sent\n");
2.1.2.4、读取服务器的响应
//读取服务器的响应
while ((valread = read(sock, buffer, BUFFER_SIZE - 1)) > 0) {
buffer[valread] = '\0';
printf("Received from server: %s\n", buffer);
}
if (valread < 0) {
perror("Read failed");
}
2.1.2.5、关闭套接字
//关闭socket
close(sock);
2.2、基于socket编程的TCP通信流程图
2.3、基于socket编程的TCP示例
2.3.1、服务端(service.c)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[BUFFER_SIZE] = {0};
const char *hello = "Hello from server";
//创建socket文件描述符
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
//设置socket选项,允许地址重用
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("127.0.0.1");
address.sin_port = htons(PORT);
//绑定socket到端口
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
//开始监听连接
if (listen(server_fd, 3) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
//接受客户端连接
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
//读取客户端发送的数据
int valread = read(new_socket, buffer, BUFFER_SIZE);
printf("%s\n", buffer);
//发送响应给客户端
send(new_socket, hello, strlen(hello), 0);
printf("Hello message sent\n");
//关闭套接字
close(server_fd);
close(new_socket);
return 0;
}
2.3.2、客户端(client.c)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define PORT 8080
#define BUFFER_SIZE 1024
int main() {
int sock = 0;
struct sockaddr_in serv_addr;
char *hello = "Hello from client";
char buffer[BUFFER_SIZE] = {0};
int valread;
//创建socket文件描述符
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("Socket creation error");
exit(EXIT_FAILURE);
}
//设置服务器地址结构
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
//连接到服务器
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
perror("Connection failed");
exit(EXIT_FAILURE);
}
printf("Connected to server\n");
//发送数据给服务器
if (send(sock, hello, strlen(hello), 0) < 0) {
perror("Send failed");
exit(EXIT_FAILURE);
}
printf("Hello message sent\n");
//读取服务器的响应
while ((valread = read(sock, buffer, BUFFER_SIZE - 1)) > 0) {
buffer[valread] = '\0';
printf("Received from server: %s\n", buffer);
}
if (valread < 0) {
perror("Read failed");
}
//关闭socket
close(sock);
return 0;
}
三、基于socket编程的UDP通信过程
3.1、基于socket编程的UDP通信流程
3.1.1、服务端
3.1.1.1、创建socket
//创建socket
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
3.1.1.2、设置服务器地址结构
//设置服务器地址结构
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");//具体的ip地址
server_addr.sin_port = htons(SERVER_PORT);
3.1.1.3、绑定socket
//绑定socket
if (bind(sockfd, (const struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
3.1.1.4、打印监听信息
printf("Server is listening on port %d\n", SERVER_PORT);
3.1.1.5、接收数据
//接收数据
n = recvfrom(sockfd, (char *)buffer, BUFFER_SIZE, MSG_WAITALL, (struct sockaddr *)&client_addr, &len);
buffer[n] = '\0';
printf("Received from client: %s\n", buffer);
3.1.1.6、关闭socket
//关闭socket
close(sockfd);
3.1.2、客户端
3.1.2.1、创建socket
//创建socket
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
3.1.2.2、设置服务器地址结构
//设置服务器地址结构
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
if (inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr) <= 0) {
perror("Invalid address/Address not supported");
exit(EXIT_FAILURE);
}
3.1.2.3、发送数据
//发送数据
len = sendto(sockfd, (const char *)buffer, strlen(buffer), MSG_CONFIRM,(const struct sockaddr *)&server_addr, sizeof(server_addr));
if (len < 0) {
perror("sendto failed");
exit(EXIT_FAILURE);
}
3.1.2.4、打印发送信息
打印一条消息到控制台,表明数据已成功发送到服务器
printf("Message sent to server: %s\n", buffer);
3.1.2.5、关闭socket
//关闭socket
close(sockfd);
3.2、基于socket编程的UDP通信流程图
3.3、基于socket编程的UDP通信示例
3.3.1、服务端(service.c)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SERVER_PORT 8888
#define BUFFER_SIZE 1024
int main() {
int sockfd;
struct sockaddr_in server_addr, client_addr;
socklen_t len = sizeof(client_addr);
char buffer[BUFFER_SIZE];
ssize_t n;
//创建socket
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
//设置服务器地址结构
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");//具体的ip地址
server_addr.sin_port = htons(SERVER_PORT);
//绑定socket
if (bind(sockfd, (const struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
printf("Server is listening on port %d\n", SERVER_PORT);
//接收数据
n = recvfrom(sockfd, (char *)buffer, BUFFER_SIZE, MSG_WAITALL,
(struct sockaddr *)&client_addr, &len);
buffer[n] = '\0';
printf("Received from client: %s\n", buffer);
//关闭socket
close(sockfd);
return 0;
}
3.3.2、客户端(client.c)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 8888
#define BUFFER_SIZE 1024
int main() {
int sockfd;
struct sockaddr_in server_addr;
char buffer[BUFFER_SIZE] = "Hello from UDP client!";
ssize_t len;
//创建socket
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
//设置服务器地址结构
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
if (inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr) <= 0) {
perror("Invalid address/Address not supported");
exit(EXIT_FAILURE);
}
//发送数据
len = sendto(sockfd, (const char *)buffer, strlen(buffer), MSG_CONFIRM,
(const struct sockaddr *)&server_addr, sizeof(server_addr));
if (len < 0) {
perror("sendto failed");
exit(EXIT_FAILURE);
}
printf("Message sent to server: %s\n", buffer);
//关闭socket
close(sockfd);
return 0;
}