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概述
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语言代码,且代码已附在文章最下面)
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;
}