本文使用C语言,在Centos实现Socket两种通信类型(TCP和UDP)
文章目录
- 一、安装gcc
- 二、使用TCP协议,实现Socket(SOCKE_STREAM)流式通信
- 1. 编写`TCP_server.c`
- 函数和参数解释
- 2.编写`TCP_client.c`
- 函数和参数解释
- 3. 编译并运行上述两个文件
- 3.1 编译
- 3.2 运行(启动两个终端,分别运行)
- 测试
- 三、使用数据报协议UDP,实现数据报socket(SOCK_DGRAM)通信
- 1. 编写`UDP_server.c`
- 函数和参数解释
- 2.编写`UDP_client.c`
- 函数和参数解释
- 3.编译运行及测试,参考TCP即可
一、安装gcc
如果Centos没有C语言编译器,使用下面命令进行下载安装
yum -y install gcc
使用下列命令查看安装版本
gcc --version
如安装失败,请寻找其他教程
二、使用TCP协议,实现Socket(SOCKE_STREAM)流式通信
1. 编写TCP_server.c
#include <sys/types.h> // 包含基本系统数据类型
#include <sys/socket.h> // 包含socket函数及数据结构
#include <netinet/in.h> // 定义数据结构sockaddr_in
#include <arpa/inet.h> // 提供IP地址转换函数
#include <string.h> // 提供字符串处理函数
#include <stdlib.h> // 提供通用工具函数
#include <stdio.h> // 提供输入输出函数
#include <unistd.h> // 提供对POSIX操作系统API的访问功能
#define QUEUE 20 // 最大同时连接请求数
#define BUFFER_SIZE 1024 // 缓冲区大小
int main()
{
// 创建socket,指定IPv4协议族,流式socket
int server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
// 定义服务器地址结构
struct sockaddr_in server_sockaddr;
server_sockaddr.sin_family = AF_INET; // 地址族
server_sockaddr.sin_port = htons(8887); // 端口号,使用htons进行字节序转换
server_sockaddr.sin_addr.s_addr = inet_addr("192.168.138.133"); // 服务器IP地址
// 绑定socket
if(bind(server_sockfd, (struct sockaddr *)&server_sockaddr, sizeof(server_sockaddr)) == -1)
{
perror("bind"); // 如果绑定失败,打印错误信息
exit(1); // 退出程序
}
// 监听网络连接
if(listen(server_sockfd, QUEUE) == -1)
{
perror("listen"); // 如果监听失败,打印错误信息
exit(1); // 退出程序
}
// 定义客户端地址结构
char buffer[BUFFER_SIZE];
struct sockaddr_in client_addr;
socklen_t length = sizeof(client_addr);
// 接受客户端连接
int conn = accept(server_sockfd, (struct sockaddr *)&client_addr, &length);
if(conn < 0)
{
perror("connect"); // 如果连接失败,打印错误信息
exit(1); // 退出程序
}
// 数据交换循环
while(1)
{
memset(buffer, 0, sizeof(buffer)); // 清空缓冲区
int len = recv(conn, buffer, sizeof(buffer), 0); // 接收数据
if(strcmp(buffer, "exit\n") == 0) // 如果接收到"exit"命令,则退出循环
break;
fputs(buffer,{"code":504,"success":false,"message":"Gateway timeout has occurred"} stdout); // 将接收到的数据打印到标准输出
send(conn, buffer, len, 0); // 将接收到的数据发送回客户端
}
// 关闭连接
close(conn);
close(server_sockfd);
return 0;
}
函数和参数解释
-
socket(int domain, int type, int protocol)
: 创建一个新的socket。domain
: 指定协议族,这里是AF_INET
(IPv4网络协议)。type
: 指定socket类型,这里是SOCK_STREAM
(提供顺序化、可靠、双向的基于连接的字节流)。protocol
: 指定具体协议,0
表示自动选择type
对应的默认协议,这里是TCP。
-
bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
: 将socket绑定到本地地址。sockfd
: socket文件描述符。addr
: 指向本地地址信息的指针。addrlen
: 地址信息的长度。
-
listen(int sockfd, int backlog)
: 开始监听网络连接请求。sockfd
: socket文件描述符。backlog
: 最大同时连接请求数。
-
accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
: 接受一个连接请求。sockfd
: socket文件描述符。addr
: 指向客户端地址信息的指针。addrlen
: 地址信息的长度。
-
recv(int sockfd, void *buf, size_t len, int flags)
: 接收数据。sockfd
: 连接的socket文件描述符。buf
: 指向接收缓冲区的指针。len
: 缓冲区的长度。flags
: 传输控制标志,这里为0
表示无特殊操作。
-
send(int sockfd, const void *buf, size_t len, int flags)
: 发送数据。sockfd
: 连接的socket文件描述符。buf
: 指向数据缓冲区的指针。len
: 要发送的数据字节数。flags
: 传输控制标志,这里为0
表示无特殊操作。
这段代码首先创建一个服务器端的socket,然后绑定到本地地址和端口上,之后监听来自客户端的连接请求。一旦接受到连接请求,服务器就会进入一个循环,接收客户端发送的数据并将其回显给客户端,直到接收到"exit"命令为止。最后,关闭客户端和服务器的socket连接。
2.编写TCP_client.c
#include <sys/types.h> // 包含基本系统数据类型
#include <sys/socket.h> // 包含socket函数及数据结构
#include <netinet/in.h> // 定义数据结构sockaddr_in
#include <arpa/inet.h> // 提供IP地址转换函数
#include <string.h> // 提供字符串处理函数
#include <stdlib.h> // 提供通用工具函数
#include <stdio.h> // 提供输入输出函数
#include <unistd.h> // 提供对POSIX操作系统API的访问功能
#define QUEUE 20 // 最大同时连接请求数
#define BUFFER_SIZE 1024 // 缓冲区大小
int main()
{
// 创建socket,指定IPv4协议族,流式socket
int sock_cli = socket(AF_INET, SOCK_STREAM, 0);
// 定义服务器地址结构
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr)); // 初始化地址结构
servaddr.sin_family = AF_INET; // 地址族
servaddr.sin_port = htons(8887); // 端口号,使用htons进行字节序转换
servaddr.sin_addr.s_addr = inet_addr("192.168.138.133"); // 服务器IP地址
// 连接服务器
if(connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
{
perror("connect"); // 如果连接失败,打印错误信息
exit(1); // 退出程序
}
char sendbuf[BUFFER_SIZE]; // 发送缓冲区
char recvbuf[BUFFER_SIZE]; // 接收缓冲区
// 数据交换循环
while(fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)
{
send(sock_cli, sendbuf, strlen(sendbuf), 0); // 发送数据
if(strcmp(sendbuf, "exit\n") == 0) // 如果输入"exit"命令,则退出循环
break;
recv(sock_cli, recvbuf, sizeof(recvbuf), 0); // 接收数据
fputs(recvbuf, stdout); // 将接收到的数据打印到标准输出
memset(sendbuf, 0, sizeof(sendbuf)); // 清空发送缓冲区
memset(recvbuf, 0, sizeof(recvbuf)); // 清空接收缓冲区
}
// 关闭socket
close(sock_cli);
return 0;
}
函数和参数解释
-
socket(int domain, int type, int protocol)
: 创建一个新的socket。domain
: 指定协议族,这里是AF_INET
(IPv4网络协议)。type
: 指定socket类型,这里是SOCK_STREAM
(提供顺序化、可靠、双向的基于连接的字节流)。protocol
: 指定具体协议,0
表示自动选择type
对应的默认协议,这里是TCP。
-
connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
: 请求连接到指定的socket。sockfd
: socket文件描述符。addr
: 指向目标主机地址信息的指针。addrlen
: 地址信息的长度。
-
send(int sockfd, const void *buf, size_t len, int flags)
: 发送数据。sockfd
: socket文件描述符。buf
: 指向数据缓冲区的指针。len
: 要发送的数据字节数。flags
: 传输控制标志,这里为0
表示无特殊操作。
-
recv(int sockfd, void *buf, size_t len, int flags)
: 接收数据。sockfd
: socket文件描述符。buf
: 指向接收缓冲区的指针。len
: 缓冲区的长度。flags
: 传输控制标志,这里为0
表示无特殊操作。
这段代码首先创建一个客户端的socket,然后连接到服务器的指定IP地址和端口上。一旦连接成功,客户端就会进入一个循环,从标准输入读取数据发送到服务器,并接收服务器的回应,直到输入"exit"命令为止。最后,关闭socket连接。
3. 编译并运行上述两个文件
3.1 编译
gcc TCP_server.c -o TCP_server
gcc TCP_client.c -o TCP_client
3.2 运行(启动两个终端,分别运行)
./TCP_server
./TCP_client
启动成功后,如图所示:
测试
在client端输入test
按下回车,可以看到,server端收到test
三、使用数据报协议UDP,实现数据报socket(SOCK_DGRAM)通信
1. 编写UDP_server.c
#include <sys/types.h> // 包含系统数据类型定义
#include <sys/socket.h> // 提供socket函数及相关数据结构
#include <netinet/in.h> // 包含IP地址和端口号数据结构
#include <arpa/inet.h> // 提供IP地址转换函数
#include <string.h> // 提供字符串处理函数
#include <stdlib.h> // 提供标准库函数
#include <sys/shm.h> // 提供共享内存相关函数
#include <stdio.h> // 提供输入输出函数
#include <fcntl.h> // 提供文件控制函数
#include <unistd.h> // 提供POSIX操作系统API
#define RECVLENTH 120 // 定义接收数据长度
#define SENDLENTH 120 // 定义发送数据长度
int main(int argc, char **argv)
{
int sockefd = socket(AF_INET, SOCK_DGRAM, 0); // 创建一个UDP socket
if(sockefd == -1)
{
perror("socket failed!"); // 输出错误信息
}
struct sockaddr_in saddr, caddr; // 定义服务器地址结构和客户端地址结构
memset(&saddr, 0, sizeof(struct sockaddr_in)); // 初始化服务器地址结构
saddr.sin_family = AF_INET; // 设置地址族为IPv4
saddr.sin_port = htons(6666); // 设置端口号,使用htons进行字节序转换
saddr.sin_addr.s_addr = inet_addr("192.168.138.133"); // 设置服务器IP地址
int ret = bind(sockefd, (struct sockaddr*)&saddr, sizeof(struct sockaddr)); // 将socket绑定到服务器地址
if(ret == -1)
{
perror("bind failed!"); // 输出错误信息
}
char buf[RECVLENTH]; // 定义接收数据的缓冲区
memset(buf, 0, RECVLENTH); // 初始化接收缓冲区
int size = sizeof(struct sockaddr); // 获取地址结构的长度
recvfrom(sockefd, buf, RECVLENTH, 0, (struct sockaddr*)&caddr, &size); // 接收客户端发送的数据
printf("[server recv]:%s\n", buf); // 打印接收到的数据
char buf1[SENDLENTH] = {"hello client!"}; // 准备要发送的数据
sendto(sockefd, buf1, strlen(buf1), 0, (struct sockaddr*)&caddr, sizeof(struct sockaddr)); // 发送数据给客户端
close(sockefd); // 关闭socket连接
return 0;
}
函数和参数解释
-
socket(AF_INET, SOCK_DGRAM, 0)
: 创建一个UDP socket。AF_INET
: 指定协议族为IPv4。SOCK_DGRAM
: 指定socket类型为数据报套接字,即UDP。0
: 传输协议,这里为默认值。
-
bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
: 将socket绑定到特定地址。sockfd
: socket文件描述符。addr
: 指向要绑定的地址结构的指针。addrlen
: 地址结构的长度。
-
recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen)
: 接收数据报。sockfd
: socket文件描述符。buf
: 接收数据的缓冲区。len
: 缓冲区长度。flags
: 接收标志,这里为0
表示无特殊操作。src_addr
: 指向发送方地址结构的指针。addrlen
: 地址结构的长度。
-
sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen)
: 发送数据报。sockfd
: socket文件描述符。buf
: 要发送的数据。len
: 数据长度。flags
: 发送标志,这里为0
表示无特殊操作。dest_addr
: 指向目标地址结构的指针。addrlen
: 地址结构的长度。
这段代码创建了一个UDP服务器端,绑定到特定地址和端口上。它接收来自客户端的数据报,然后回显"hello client!"给客户端,并关闭连接。
2.编写UDP_client.c
#include <sys/types.h> // 包含系统数据类型定义
#include <sys/socket.h> // 提供socket函数及相关数据结构
#include <netinet/in.h> // 包含IP地址和端口号数据结构
#include <arpa/inet.h> // 提供IP地址转换函数
#include <string.h> // 提供字符串处理函数
#include <stdlib.h> // 提供标准库函数
#include <sys/shm.h> // 提供共享内存相关函数
#include <stdio.h> // 提供输入输出函数
#include <fcntl.h> // 提供文件控制函数
#include <unistd.h> // 提供POSIX操作系统API
#define RECVLENTH 120 // 定义接收数据的缓冲区大小
#define SENDLENTH 120 // 定义发送数据的缓冲区大小
int main(int argc, char **argv) // 主函数入口,接收命令行参数
{
int sockefd = socket(AF_INET, SOCK_DGRAM, 0); // 创建一个UDP socket
if (sockefd == -1) // 检查socket是否创建成功
{
perror("socket failed!"); // 输出错误信息
}
struct sockaddr_in saddr, caddr; // 定义服务器地址结构和客户端地址结构
memset(&saddr, 0, sizeof(struct sockaddr_in)); // 初始化服务器地址结构
saddr.sin_family = AF_INET; // 设置地址族为IPv4
saddr.sin_port = htons(6666); // 设置端口号,使用htons进行字节序转换
saddr.sin_addr.s_addr = inet_addr("192.168.138.133"); // 设置服务器IP地址
char buf[SENDLENTH] = "hello server"; // 准备要发送的数据
sendto(sockefd, buf, strlen(buf), 0, (struct sockaddr*)&saddr, sizeof(struct sockaddr)); // 发送数据给服务器
char buf1[RECVLENTH]; // 定义接收数据的缓冲区
memset(buf1, 0, RECVLENTH); // 初始化接收缓冲区
int size = sizeof(struct sockaddr); // 获取地址结构的长度
recvfrom(sockefd, buf1, RECVLENTH, 0, (struct sockaddr*)&caddr, &size); // 接收服务器发送的数据
printf("[client recv]:%s\n", buf1); // 打印接收到的数据
close(sockefd); // 关闭socket连接
return 0; // 返回程序执行成功
}
函数和参数解释
-
socket(AF_INET, SOCK_DGRAM, 0)
: 创建一个UDP socket。AF_INET
: 指定协议族为IPv4。SOCK_DGRAM
: 指定socket类型为数据报套接字,即UDP。0
: 传输协议,这里为默认值。
-
bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
: 将socket绑定到特定地址。sockfd
: socket文件描述符。addr
: 指向要绑定的地址结构的指针。addrlen
: 地址结构的长度。
-
recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen)
: 接收数据报。sockfd
: socket文件描述符。buf
: 接收数据的缓冲区。len
: 缓冲区长度。flags
: 接收标志,这里为0
表示无特殊操作。src_addr
: 指向发送方地址结构的指针。addrlen
: 地址结构的长度。
-
sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen)
: 发送数据报。sockfd
: socket文件描述符。buf
: 要发送的数据。len
: 数据长度。flags
: 发送标志,这里为0
表示无特殊操作。dest_addr
: 指向目标地址结构的指针。addrlen
: 地址结构的长度。
这段代码创建了一个UDP客户端,向特定地址和端口发送"hello server",然后接收服务器端回复的数据并打印出来。
3.编译运行及测试,参考TCP即可
转载请注明出处
作者:BQ
主页:https://blog.csdn.net/weixin_52677672?type=blog
QQ群:958124241
Learn Together!