目录
- 前言
- 1、编程环境
- 2、编译命令
- 3、标题名前缀解释
- 4、注意事项
- 0011客户端读取服务端字符_服务端
- 0012客户端读取服务端字符_客户端
- 0021回声测试_服务端
- 0022回声测试_客户端
- 0030启动端口复用解决端口绑定失败问题
- 0041服务器不间断进行侦听通信_服务端
- 0042服务器不间断进行侦听通信_客户端
- 0050输入输出缓冲区大小
- 0061TCP的粘包问题_服务端
- 0062TCP的粘包问题_客户端
- 0071使用shutdown关闭连接_服务端
- 0072使用shutdown关闭连接_客户端
- 0081使用TCP进行文件传输_服务端
- 0082使用TCP进行文件传输_客户端
- 0091网络字节序转换函数1
- 0091网络字节序转换函数2
- 0100进行域名解析
前言
1、编程环境
编码所用IDE:VScode 1.87.0
编译工具:gcc version 11.4.0
运行环境:
1、Windows Subsystem for Linux (WSL) 2
2、Ubuntu 22.04.4 LTS
2、编译命令
如无特别说明,通用编译命令为:
gcc -o server -g -Wall -std=gnu99 filename.c
或
gcc -o client -g -Wall -std=gnu99 filename.c
3、标题名前缀解释
XXX1或XXX2中,XXX代表一个主题,凡是具有相同的XXX,都是同一主题。
1代表服务端内容(代码),2代表客户端内容(代码)。
4、注意事项
所有代码都需要先运行服务端,而后再运行客户端,或者先运行接收端,再运行发送端。
0011客户端读取服务端字符_服务端
相关代码:
#include <stdio.h> // 引入标准输入输出库
#include <string.h> // 引入字符串操作库
#include <stdlib.h> // 引入标准库
#include <unistd.h> // 引入unistd库,主要用到close函数
#include <arpa/inet.h> // 引入arpa/inet.h库,主要用到socket地址操作函数
#include <sys/socket.h> // 引入sys/socket.h库,主要用到socket函数
#include <netinet/in.h> // 引入netinet/in.h库,主要用到socket地址结构体
int main(int argc, char const *argv[])
{
int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // 创建TCP套接字
struct sockaddr_in serv_addr; // 定义服务器socket地址结构体
memset(&serv_addr, 0, sizeof(serv_addr)); // 初始化服务器socket地址结构体为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(1234); // 设置服务器端口号为1234
bind(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); // 绑定socket地址到套接字
listen(serv_sock, 10); // 监听套接字,最大连接数为10
struct sockaddr_in clnt_addr; // 定义客户端socket地址结构体
socklen_t clnt_addr_size = sizeof(clnt_addr); // 定义客户端socket地址结构体大小
int clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_addr, &clnt_addr_size); // 接受客户端连接
char str[] = "这是服务的的信息。\n"; // 定义发送给客户端的信息
write(clnt_sock, str, sizeof(str)); // 向客户端发送信息
close(clnt_sock); // 关闭客户端套接字
close(serv_sock); // 关闭服务器套接字
return 0; // 程序正常退出
}
0012客户端读取服务端字符_客户端
相关代码:
#include <stdio.h> // 引入标准输入输出库
#include <string.h> // 引入字符串操作库
#include <unistd.h> // 引入Unix标准函数库
#include <stdlib.h> // 引入标准库定义
#include <arpa/inet.h> // 引入IP地址转换库
#include <sys/socket.h> // 引入套接字库
int main(int argc, char const *argv[])
{
int sock = socket(AF_INET, SOCK_STREAM, 0); // 创建一个IPv4的TCP套接字
struct sockaddr_in serv_addr; // 定义一个IPv4的套接字地址结构
memset(&serv_addr, 0, sizeof(sock)); // 将套接字地址结构清零,避免脏数据
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(1234); // 设置服务器的端口号为1234,并转换为网络字节序
connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); // 连接到服务器
char buffer[128]; // 定义一个缓冲区用于接收数据
read(sock, buffer, sizeof(buffer) - 1); // 从套接字读取数据到缓冲区,留一个字节用于字符串结束符
printf("客户端读取到的信息为:%s\n", buffer); // 打印从服务器接收到的信息
close(sock); // 关闭套接字
return 0; // 程序结束
}
运行结果:
0021回声测试_服务端
相关代码:
#include <stdio.h> // 引入标准输入输出库
#include <string.h> // 引入字符串操作库
#include <stdlib.h> // 引入标准库,提供多种函数
#include <unistd.h> // 引入Unix标准函数库
#include <arpa/inet.h> // 引入IP地址转换函数库
#include <sys/socket.h> // 引入套接字API
#include <netinet/in.h> // 引入Internet地址族相关的定义
int main(int argc, char const *argv[]) // 主函数
{
int serv_sock = socket(AF_INET, SOCK_STREAM, 0); // 创建TCP套接字
struct sockaddr_in serv_addr; // 定义服务器地址结构
memset(&serv_addr, 0, sizeof(serv_addr)); // 初始化地址结构为0
serv_addr.sin_family = AF_INET; // 设置地址家族为IPv4
serv_addr.sin_port = htons(1234); // 设置端口号为1234,网络字节序
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 设置IP地址为本地环回地址
if (bind(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) != 0) // 绑定地址到套接字
{
perror("绑定地址出错!"); // 如果绑定失败,打印错误信息
return -1;
}
listen(serv_sock, 1); // 监听套接字,最大连接数为1
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 buffer[1024]; // 定义缓冲区
memset(buffer, 0, sizeof(buffer)); // 初始化缓冲区为0
read(clnt_sock, buffer, sizeof(buffer)); // 从客户端读取数据到缓冲区
printf("客户端发来的信息:%s\n", buffer); // 打印客户端发来的信息
write(clnt_sock, buffer, sizeof(buffer)); // 将缓冲区中的数据写回客户端
close(clnt_sock); // 关闭客户端套接字
close(serv_sock); // 关闭服务器套接字
printf("关闭连接成功!\n"); // 打印关闭连接成功的消息
return 0; // 程序结束
}
0022回声测试_客户端
相关代码:
#include <stdio.h> // 引入标准输入输出库
#include <string.h> // 引入字符串操作库
#include <unistd.h> // 引入Unix标准函数库
#include <stdlib.h> // 引入标准库,提供多种函数
#include <arpa/inet.h> // 引入IP地址转换函数库
#include <sys/socket.h> // 引入套接字API
int main(int argc, char const *argv[]) // 主函数
{
int clnt_sock = socket(AF_INET, SOCK_STREAM, 0); // 创建TCP套接字
struct sockaddr_in serv_addr; // 定义服务器地址结构
memset(&serv_addr, 0, sizeof(serv_addr)); // 初始化地址结构为0
serv_addr.sin_family = AF_INET; // 设置地址家族为IPv4
serv_addr.sin_port = htons(1234); // 设置端口号为1234,网络字节序
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 设置IP地址为本地环回地址
if (connect(clnt_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) != 0) // 连接到服务器
{
perror("连接失败!"); // 如果连接失败,打印错误信息
return -1; // 返回-1表示连接失败
}
char buffer[1024]; // 定义缓冲区
memset(buffer, 0, sizeof(buffer)); // 初始化缓冲区为0
printf("连接成功!输入发送的内容:\n"); // 提示用户输入内容
scanf("%s", buffer); // 从标准输入读取字符串到缓冲区
write(clnt_sock, buffer, sizeof(buffer)); // 将缓冲区中的数据发送到服务器
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
read(clnt_sock, buffer, sizeof(buffer)); // 从服务器读取数据到缓冲区
printf("接收到的信息为:%s\n", buffer); // 打印接收到的信息
close(clnt_sock); // 关闭客户端套接字
printf("关闭连接!\n"); // 打印关闭连接的消息
return 0; // 程序结束
}
运行结果:
0030启动端口复用解决端口绑定失败问题
相关代码:
#include <stdio.h> // 引入标准输入输出库
#include <string.h> // 引入字符串操作库
#include <stdlib.h> // 引入标准库,提供多种函数
#include <unistd.h> // 引入Unix标准函数库
#include <arpa/inet.h> // 引入IP地址转换函数库
#include <sys/socket.h> // 引入套接字API
#include <netinet/in.h> // 引入Internet地址族相关的定义
int main(int argc, char const *argv[]) // 主函数
{
int serv_sock1 = socket(AF_INET, SOCK_STREAM, 0); // 创建第一个TCP套接字
// 设置SO_REUSEADDR来允许端口复用
int reuse = 1;
if (setsockopt(serv_sock1, SOL_SOCKET, SO_REUSEADDR, (const void *)&reuse, sizeof(reuse)) < 0)
{
perror("设置SO_REUSEADDR 1 失败"); // 如果设置失败,打印错误信息
return -1; // 返回-1表示设置失败
}
struct sockaddr_in serv_addr1; // 定义第一个服务器地址结构
memset(&serv_addr1, 0, sizeof(serv_addr1)); // 初始化地址结构为0
serv_addr1.sin_family = AF_INET; // 设置地址家族为IPv4
serv_addr1.sin_port = htons(1234); // 设置端口号为1234,网络字节序
serv_addr1.sin_addr.s_addr = inet_addr("127.0.0.1"); // 设置IP地址为本地环回地址
if (bind(serv_sock1, (struct sockaddr *)&serv_addr1, sizeof(serv_addr1)) != 0) // 绑定地址到第一个套接字
{
perror("serv_sock1 绑定sock失败!"); // 如果绑定失败,打印错误信息
return -1; // 返回-1表示绑定失败
}
int serv_sock2 = socket(AF_INET, SOCK_STREAM, 0); // 创建第二个TCP套接字
// 同样为第二个套接字设置SO_REUSEADDR
if (setsockopt(serv_sock2, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
{
perror("设置SO_REUSEADDR 2 失败"); // 如果设置失败,打印错误信息
return -1; // 返回-1表示设置失败
}
if (bind(serv_sock2, (struct sockaddr *)&serv_addr1, sizeof(serv_addr1)) != 0) // 绑定地址到第二个套接字
{
perror("serv_sock2 绑定sock失败!"); // 如果绑定失败,打印错误信息
return -1; // 返回-1表示绑定失败
}
printf("端口复用成功!\n"); // 打印端口复用成功的消息
close(serv_sock1); // 关闭第一个套接字
close(serv_sock2); // 关闭第二个套接字
return 0; // 程序结束
}
运行结果:
0041服务器不间断进行侦听通信_服务端
相关代码:
#include <stdio.h> // 引入标准输入输出库
#include <string.h> // 引入字符串操作库
#include <stdlib.h> // 引入标准库,提供多种函数
#include <unistd.h> // 引入Unix标准函数库
#include <arpa/inet.h> // 引入IP地址转换函数库
#include <sys/socket.h> // 引入套接字API
#include <netinet/in.h> // 引入Internet地址族相关的定义
int main(int argc, char const *argv[]) // 主函数
{
int serv_sock = socket(AF_INET, SOCK_STREAM, 0); // 创建TCP套接字
struct sockaddr_in serv_addr; // 定义服务器地址结构
memset(&serv_addr, 0, sizeof(serv_addr)); // 初始化地址结构为0
serv_addr.sin_family = AF_INET; // 设置地址家族为IPv4
serv_addr.sin_port = htons(1234); // 设置端口号为1234,网络字节序
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 设置服务器IP为本地环回地址
bind(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); // 绑定地址到套接字
listen(serv_sock, 3); // 监听套接字,最大连接数为3
while (1) // 无限循环等待客户端连接
{
char buffer[128]; // 定义缓冲区用于接收和发送数据
memset(buffer, 0, sizeof(buffer)); // 初始化缓冲区为0
struct sockaddr_in clnt_addr; // 定义客户端地址结构
socklen_t clnt_sock_size = sizeof(clnt_addr); // 定义客户端地址结构大小
int clnt_sock = accept(serv_sock, // 接受客户端连接
(struct sockaddr *)&clnt_addr,
&clnt_sock_size);
read(clnt_sock, buffer, sizeof(buffer)); // 读取客户端发送的数据
printf("客户端发来的消息:%s\n", buffer); // 打印客户端发送的消息
write(clnt_sock, buffer, sizeof(buffer)); // 将收到的消息写回客户端
close(clnt_sock); // 关闭与客户端的连接
if (strcmp(buffer, "exit") == 0) // 如果客户端发送的消息是"exit"
{
break; // 退出循环
}
}
close(serv_sock); // 关闭服务器套接字
printf("关闭一切连接。\n"); // 打印关闭连接的信息
return 0; // 程序结束
}
0042服务器不间断进行侦听通信_客户端
相关代码:
#include <stdio.h> // 引入标准输入输出库
#include <string.h> // 引入字符串操作库
#include <unistd.h> // 引入Unix标准函数库
#include <stdlib.h> // 引入标准库定义
#include <arpa/inet.h> // 引入IP地址转换库
#include <sys/socket.h> // 引入套接字库
int main(int argc, char const *argv[])
{
struct sockaddr_in serv_addr; // 定义服务器地址结构体
memset(&serv_addr, 0, sizeof(serv_addr)); // 初始化服务器地址结构体为0
serv_addr.sin_family = AF_INET; // 设置地址家族为IPv4
serv_addr.sin_port = htons(1234); // 设置端口号为1234,网络字节序
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 设置服务器IP地址为本地回环地址
while (1)
{ // 循环处理连接
int clnt_sock = socket(AF_INET, SOCK_STREAM, 0); // 创建客户端套接字
if (connect(clnt_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) != 0)
{
perror("连接失败!"); // 连接失败,打印错误信息
}
char buffer[1024]; // 定义缓冲区
memset(buffer, 0, sizeof(buffer)); // 初始化缓冲区为0
printf("连接成功!输入发送的内容:\n"); // 提示用户输入内容
scanf("%s", buffer); // 从标准输入读取字符串到缓冲区
write(clnt_sock, buffer, sizeof(buffer)); // 向服务器发送数据
memset(buffer, 0, sizeof(buffer)); // 重置缓冲区
read(clnt_sock, buffer, sizeof(buffer)); // 从服务器读取数据到缓冲区
printf("接收到的信息为:%s\n", buffer); // 打印接收到的信息
close(clnt_sock); // 关闭套接字
if (strcmp(buffer, "exit") == 0)
{ // 如果接收到的信息是"exit"
break; // 退出循环
}
}
printf("关闭连接!\n"); // 打印关闭连接信息
return 0; // 程序结束返回0
}
运行结果:
0050输入输出缓冲区大小
相关代码:
#include <stdio.h> // 引入标准输入输出库
#include <arpa/inet.h> // 引入IP地址转换函数库
#include <sys/socket.h> // 引入套接字API
int main(int argc, char const *argv[]) // 主函数
{
int serv_sock = socket(AF_INET, SOCK_STREAM, 0); // 创建TCP套接字
unsigned int opt_val; // 定义一个无符号整数变量用于存储选项值
socklen_t opt_len = sizeof(int); // 定义一个socklen_t类型的变量用于存储选项长度
getsockopt(serv_sock, SOL_SOCKET, SO_SNDBUF, (char *)&opt_val, &opt_len); // 获取发送缓冲区大小
printf("发送缓冲区大小: %d\n", opt_val); // 打印发送缓冲区大小
getsockopt(serv_sock, SOL_SOCKET, SO_RCVBUF, (void *)&opt_val, &opt_len); // 获取接收缓冲区大小
printf("接收缓冲区大小: %d\n", opt_val); // 打印接收缓冲区大小
return 0; // 程序结束
}
运行结果:
0061TCP的粘包问题_服务端
相关代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define BUF_SIZE 100
int main(int argc, char const *argv[])
{
// 创建套接字
int servSock = socket(AF_INET, SOCK_STREAM, 0);
// 绑定套接字
struct sockaddr_in sockAddr;
memset(&sockAddr, 0, sizeof(sockAddr)); // 每个字节都用0填充
sockAddr.sin_family = AF_INET; // 使用IPv4地址
sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 具体的IP地址
sockAddr.sin_port = htons(1234); // 端口
bind(servSock, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
// 进入监听状态
listen(servSock, 20);
// 接收客户端请求
struct sockaddr_in clntAddr;
socklen_t nSize = sizeof(clntAddr);
char buffer[BUF_SIZE] = {0}; // 缓冲区
int clntSock = accept(servSock, (struct sockaddr *)&clntAddr, &nSize);
// 注意暂停10秒!在这10秒期间,客户端发送过来的任意数据都会堆积在缓冲区中
sleep(10);
// 接收客户端发来的数据,并原样返回
int recvLen = recv(clntSock, buffer, BUF_SIZE, 0);
send(clntSock, buffer, recvLen, 0);
// 关闭套接字并终止DLL的使用
close(clntSock);
close(servSock);
return 0;
}
0062TCP的粘包问题_客户端
相关代码:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 100
int main(int argc, char const *argv[])
{
// 向服务器发起请求
struct sockaddr_in sockAddr;
memset(&sockAddr, 0, sizeof(sockAddr)); // 每个字节都用0填充
sockAddr.sin_family = PF_INET;
sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
sockAddr.sin_port = htons(1234);
// 创建套接字
int sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
connect(sock, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
// 获取用户输入的字符串并发送给服务器
char bufSend[BUF_SIZE] = {0};
printf("输入内容: ");
scanf("%s", bufSend);
for (int i = 0; i < 3; i++)
{
send(sock, bufSend, strlen(bufSend), 0);
}
// 接收服务器传回的数据
char bufRecv[BUF_SIZE] = {0};
recv(sock, bufRecv, BUF_SIZE, 0);
// 输出接收到的数据
printf("来源于服务器的信息为: %s\n", bufRecv);
close(sock); // 关闭套接字
return 0;
}
运行结果:
0071使用shutdown关闭连接_服务端
相关代码:
#include <stdio.h> // 引入标准输入输出库
#include <stdlib.h> // 引入标准库,提供多种函数
#include <string.h> // 引入字符串操作库
#include <unistd.h> // 引入Unix标准函数库
#include <arpa/inet.h> // 引入IP地址转换函数库
#include <sys/socket.h> // 引入套接字API
#include <netinet/in.h> // 引入Internet地址族相关的定义
int main(int argc, char const *argv[]) // 主函数
{
int serv_sock = socket(AF_INET, SOCK_STREAM, 0); // 创建TCP套接字
struct sockaddr_in serv_addr; // 定义服务器地址结构
memset(&serv_addr, 0, sizeof(serv_addr)); // 初始化地址结构为0
serv_addr.sin_family = AF_INET; // 设置地址家族为IPv4
serv_addr.sin_port = htons(1234); // 设置端口号为1234,网络字节序
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 设置服务器IP为本地环回地址
bind(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); // 绑定地址到套接字
listen(serv_sock, 1); // 监听套接字,最大连接数为1
struct sockaddr_in clnt_addr; // 定义客户端地址结构
socklen_t clnt_size = sizeof(clnt_addr); // 定义客户端地址结构大小
memset(&clnt_addr, 0, sizeof(clnt_addr)); // 初始化客户端地址结构为0
int clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_addr, &clnt_size); // 接受客户端连接
char buffer[128]; // 定义缓冲区用于接收和发送数据
memset(buffer, 0, sizeof(buffer)); // 初始化缓冲区为0
read(clnt_sock, buffer, sizeof(buffer)); // 读取客户端发送的数据
printf("客户端的数据为:%s\n", buffer); // 打印客户端发送的数据
write(clnt_sock, buffer, sizeof(buffer)); // 将收到的数据写回客户端
// shutdown 仅关闭连接,但没释放套接字资源
shutdown(clnt_sock, SHUT_RDWR); // 关闭客户端套接字的读写操作
shutdown(serv_sock, SHUT_RDWR); // 关闭服务器套接字的读写操作
// close 不仅关闭连接,还释放所有套接字资源
close(clnt_sock); // 关闭客户端套接字
close(serv_sock); // 关闭服务器套接字
printf("关闭已连接\n"); // 打印关闭连接的信息
return 0; // 程序结束
}
0072使用shutdown关闭连接_客户端
相关代码:
#include <stdio.h> // 引入标准输入输出库
#include <stdlib.h> // 引入标准库定义
#include <string.h> // 引入字符串操作库
#include <unistd.h> // 引入Unix标准函数库
#include <arpa/inet.h> // 引入IP地址转换库
#include <sys/socket.h> // 引入套接字库
#include <netinet/in.h> // 引入网络结构体定义
int main(int argc, char const *argv[])
{
int clnt_sock = socket(AF_INET, SOCK_STREAM, 0); // 创建客户端套接字
struct sockaddr_in serv_addr; // 定义服务器地址结构体
memset(&serv_addr, 0, sizeof(serv_addr)); // 初始化服务器地址结构体为0
serv_addr.sin_family = AF_INET; // 设置地址家族为IPv4
serv_addr.sin_port = htons(1234); // 设置端口号为1234,网络字节序
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 设置服务器IP地址为本地回环地址
if (connect(clnt_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) != 0)
{
perror("连接错误!"); // 连接失败,打印错误信息
return -1; // 返回错误码-1
}
char buffer[128]; // 定义缓冲区
memset(buffer, 0, sizeof(buffer)); // 初始化缓冲区为0
printf("请输入给服务端发送的数据信息:\n"); // 提示用户输入数据
scanf("%s", buffer); // 从标准输入读取字符串到缓冲区
write(clnt_sock, buffer, sizeof(buffer)); // 向服务器发送数据
memset(buffer, 0, sizeof(buffer)); // 重置缓冲区
read(clnt_sock, buffer, sizeof(buffer)); // 从服务器读取数据到缓冲区
printf("从服务端读取到的数据为:%s\n", buffer); // 打印接收到的数据
// shutdown 仅关闭连接,但没释放套接字资源
shutdown(clnt_sock, SHUT_RDWR);
// close 不仅关闭连接,还释放所有套接字资源
close(clnt_sock);
printf("关闭已连接\n"); // 打印关闭连接信息
return 0; // 程序结束返回0
}
运行结果:
0081使用TCP进行文件传输_服务端
注意!要确保服务器存在该文件!
相关代码:
#include <stdio.h> // 引入标准输入输出库
#include <unistd.h> // 引入Unix标准函数库
#include <stdlib.h> // 引入标准库,提供多种函数
#include <string.h> // 引入字符串操作库
#include <arpa/inet.h> // 引入IP地址转换函数库
#include <sys/socket.h> // 引入套接字API
#include <netinet/in.h> // 引入Internet地址族相关的定义
#define BUF_SIZE 1024 // 定义缓冲区大小为1024字节
int main(int argc, char const *argv[]) // 主函数
{
char *filename = "./picture.webp"; // 指定要传输的文件名
FILE *fp = fopen(filename, "rb"); // 以二进制读取方式打开文件
if (fp == NULL) // 如果文件打开失败
{
perror("文件不存在!"); // 打印错误信息
return -1; // 返回-1表示程序执行失败
}
int serv_sock = socket(AF_INET, SOCK_STREAM, 0); // 创建TCP套接字
struct sockaddr_in serv_addr; // 定义服务器地址结构
memset(&serv_addr, 0, sizeof(serv_addr)); // 初始化地址结构为0
serv_addr.sin_family = AF_INET; // 设置地址家族为IPv4
serv_addr.sin_port = htons(1234); // 设置端口号为1234,网络字节序
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 设置服务器IP为本地环回地址
bind(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); // 绑定地址到套接字
listen(serv_sock, 1); // 监听套接字,最大连接数为1
struct sockaddr_in clnt_addr; // 定义客户端地址结构
socklen_t clnt_addr_size = sizeof(clnt_addr); // 定义客户端地址结构大小
memset(&clnt_addr, 0, sizeof(clnt_addr)); // 初始化客户端地址结构为0
int clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_addr, &clnt_addr_size); // 接受客户端连接
char buffer[BUF_SIZE] = {0}; // 定义缓冲区用于读取文件内容
int read_data_size = 0; // 定义读取数据大小的变量
while ((read_data_size = fread(buffer, 1, BUF_SIZE, fp)) > 0) // 循环读取文件内容到缓冲区
{
send(clnt_sock, buffer, read_data_size, 0); // 发送缓冲区中的数据到客户端
}
// 给客户端发FIN包,告诉客户端已经发送完毕
shutdown(clnt_sock, SHUT_RDWR); // 关闭客户端套接字的读写操作
close(serv_sock); // 关闭服务器套接字
close(clnt_sock); // 关闭客户端套接字
fclose(fp); // 关闭文件
printf("数据传输完毕。\n"); // 打印数据传输完成的信息
return 0; // 程序结束
}
0082使用TCP进行文件传输_客户端
相关代码:
#include <stdio.h> // 引入标准输入输出库
#include <unistd.h> // 引入Unix标准函数库
#include <stdlib.h> // 引入标准库定义
#include <string.h> // 引入字符串操作库
#include <arpa/inet.h> // 引入IP地址转换库
#include <sys/socket.h> // 引入套接字库
#include <netinet/in.h> // 引入网络结构体定义
#define BUF_SIZE 1024 // 定义缓冲区大小为1024字节
int main(int argc, char const *argv[])
{
char buffer[BUF_SIZE] = {0}; // 定义并初始化缓冲区
printf("请输入文件路径和文件名:\n"); // 提示用户输入文件路径和文件名
scanf("%s", buffer); // 从标准输入读取文件路径和文件名到缓冲区
FILE *fp = fopen(buffer, "wb"); // 以二进制写模式打开文件
if (fp == NULL)
{
perror("打开文件失败!"); // 打开文件失败,打印错误信息
return -1; // 返回错误码-1
}
int clnt_sock = socket(AF_INET, SOCK_STREAM, 0); // 创建客户端套接字
struct sockaddr_in serv_addr; // 定义服务器地址结构体
memset(&serv_addr, 0, sizeof(serv_addr)); // 初始化服务器地址结构体为0
serv_addr.sin_family = AF_INET; // 设置地址家族为IPv4
serv_addr.sin_port = htons(1234); // 设置端口号为1234,网络字节序
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 设置服务器IP地址为本地回环地址
connect(clnt_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); // 连接服务器
memset(buffer, 0, BUF_SIZE); // 重置缓冲区
int receive_data_size = 0; // 定义接收数据大小变量
while ((receive_data_size = recv(clnt_sock, buffer, BUF_SIZE, 0)) > 0) // 循环接收数据直到没有数据可接收
{
fwrite(buffer, receive_data_size, 1, fp); // 将接收到的数据写入文件
}
fclose(fp); // 关闭文件
close(clnt_sock); // 关闭套接字
printf("数据接收完毕。\n"); // 打印数据接收完成信息
return 0; // 程序结束返回0
}
运行结果:
0091网络字节序转换函数1
相关代码:
#include <stdio.h> // 引入标准输入输出库
#include <stdlib.h> // 引入标准库,提供多种函数
#include <arpa/inet.h> // 引入IP地址转换函数库
#include <sys/socket.h> // 引入套接字API
#include <netinet/in.h> // 引入Internet地址族相关的定义
int main(int argc, char const *argv[]) // 主函数
{
unsigned short host_port = 0x1234, net_port; // 定义主机字节序的端口号和网络字节序的端口号
unsigned long host_addr = 0x12345678, net_addr; // 定义主机字节序的IP地址和网络字节序的IP地址
net_port = htons(host_port); // 将主机字节序的端口号转换为网络字节序
net_addr = htonl(host_addr); // 将主机字节序的IP地址转换为网络字节序
printf("主机端口为:%#x\n", host_port); // 打印主机字节序的端口号
printf("网络端口为:%#x\n", net_port); // 打印网络字节序的端口号
printf("主机地址为:%#lx\n", host_addr); // 打印主机字节序的IP地址
printf("网络地址为:%#lx\n", net_addr); // 打印网络字节序的IP地址
return 0; // 程序结束
}
运行结果:
0091网络字节序转换函数2
相关代码:
#include <stdio.h> // 引入标准输入输出库
#include <stdlib.h> // 引入标准库定义
#include <arpa/inet.h> // 引入IP地址转换库
#include <sys/socket.h> // 引入套接字库
#include <netinet/in.h> // 引入网络结构体定义
int main(int argc, char const *argv[])
{
char *addr1 = "1.2.3.4"; // 定义一个有效的IP地址字符串
char *addr2 = "1.2.3.256"; // 定义一个无效的IP地址字符串进行测试
unsigned long conv_addr = inet_addr(addr1); // 将IP地址字符串转换为网络字节序的整数
if (conv_addr == INADDR_NONE) // 如果转换失败,inet_addr返回INADDR_NONE
{
perror("转换错误!"); // 打印错误信息
}
else
{
printf("网络地址为:%#lx\n", conv_addr); // 打印转换后的网络地址
}
conv_addr = inet_addr(addr2); // 尝试转换无效的IP地址字符串
// inet_addr函数可以检测出错误的地址并返回INADDR_NONE
if (conv_addr == INADDR_NONE)
{
perror("转换错误!"); // 打印错误信息
}
else
{
printf("网络地址为:%#lx\n", conv_addr); // 打印转换后的网络地址
}
return 0; // 程序结束返回0
}
运行结果:
0100进行域名解析
相关代码:
#include <stdio.h> // 引入标准输入输出库
#include <arpa/inet.h> // 引入IP地址转换函数库
#include <netdb.h> // 引入网络数据库操作库,包含gethostbyname函数和struct hostent结构体
int main(int argc, char const *argv[])
{
struct hostent *host = gethostbyname("www.baidu.com"); // 使用gethostbyname函数获取网址"www.baidu.com"的主机信息
if (host == NULL) // 如果获取主机信息失败
{
perror("解析网址失败!"); // 打印错误信息
return -1; // 返回-1表示程序执行失败
}
for (int i = 0; host->h_aliases[i]; i++) // 遍历地址别名列表
{
printf("地址别名 %i 为:%s\n", i, host->h_aliases[i]); // 打印每个地址别名
}
printf("地址类型为:%s\n", (host->h_addrtype == AF_INET) ? "IPV4" : "IPV6"); // 打印地址类型
for (int i = 0; host->h_addr_list[i]; i++) // 遍历IP地址列表
{
printf("IP地址 %d:%s\n", i + 1, inet_ntoa(*(struct in_addr *)host->h_addr_list[i])); // 打印每个IP地址
}
return 0; // 程序结束
}
运行结果: