单线程消息发送接收
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
# 头文件说明
|
||||
|
||||
### sys/types.h
|
||||
|
||||
> sys/types.h是一个头文件,定义了一些基本的系统数据类型和结构体。它通常被包含在其他系统头文件中,比如socket.h、unistd.h等等。
|
||||
>
|
||||
> 在这个头文件中,定义了一些重要的数据类型,例如:
|
||||
>
|
||||
> - size_t:表示无符号整型数,用于存储对象的大小。
|
||||
> - ssize_t:表示有符号整型数,用于存储一些系统调用返回值的大小和状态。
|
||||
> - pid_t:表示进程ID,用于标识当前进程或者其他进程。
|
||||
> - off_t:表示文件偏移量,用于指示文件中的位置。
|
||||
> - time_t:表示时间戳,用于记录某个事件发生的时间。
|
||||
> - mode_t:表示文件权限掩码,用于定义文件的读写执行权限等信息。
|
||||
>
|
||||
> 除此之外,sys/types.h还定义了一些与文件描述符、信号、套接字等相关的结构体。这些结构体包括fd_set、sigevent、itimerval、timespec等等,可用于进行多路复用、事件驱动等高级操作。
|
||||
>
|
||||
> 总之,sys/types.h是一个非常重要的头文件,在系统编程和网络编程中经常被使用。通过定义各种基本数据类型和结构体,它为程序员提供了方便的系统级别的访问接口,使得开发更加高效和灵活。
|
||||
|
||||
### sys/socket.h
|
||||
|
||||
> sys/socket.h是一个C语言标准库头文件,它提供了访问底层套接字接口的函数和数据类型。在网络编程中,我们使用这个头文件来创建、绑定、监听、连接、发送和接收套接字等操作。
|
||||
>
|
||||
> 该头文件中定义了一系列函数原型,包括socket、bind、listen、connect、send、recv等等套接字相关的函数,以及sockaddr、sockaddr_in等结构体类型,用于表示套接字地址信息。这些函数和结构体提供了基本的套接字操作,可以实现客户端和服务器之间的数据交换和通信。
|
||||
>
|
||||
> 除此之外,sys/socket.h还定义了一些常量和枚举类型,例如SOCK_STREAM、SOCK_DGRAM等,用于指定套接字的类型和传输协议。这些常量和枚举类型可以帮助程序员更方便地控制套接字的行为和参数。
|
||||
>
|
||||
> 总之,sys/socket.h是网络编程中一个非常重要的头文件,通过提供各种函数和数据类型,使得程序员能够方便地进行底层套接字操作,实现可靠的网络通信。
|
||||
|
||||
### stdio.h
|
||||
|
||||
> stdio.h是一个C语言标准库头文件,提供了输入和输出相关的函数和数据类型。在C程序中,我们通常需要使用stdio.h来实现各种控制台输入输出操作,也包括一些文件读写等相关操作。
|
||||
>
|
||||
> 该头文件中定义了一系列函数原型,包括printf、scanf、puts、gets等等标准输入输出函数。这些函数可以帮助我们向屏幕输出信息、从键盘获取用户输入,实现基本的控制台输入输出功能。
|
||||
>
|
||||
> 除此之外,stdio.h还定义了FILE结构体类型,用于表示文件流。通过使用fopen、fclose、fprintf、fscanf等函数,我们可以对文件进行读写操作,并指定相应的文件名、打开模式、读写位置等参数。
|
||||
>
|
||||
> 总之,stdio.h是一个非常常用的标准库头文件,在C程序中几乎都会被用到。它提供了各种方便的输入输出函数和数据类型,可以帮助我们实现控制台交互、文件操作等各种功能。
|
||||
|
||||
### netinet/in.h
|
||||
|
||||
> netinet/in.h是一个C语言标准库头文件,主要用于定义网络通信中的地址族、套接字地址结构体等相关信息。在网络编程中,我们使用这个头文件来创建和处理IPV4和IPV6地址等操作。
|
||||
>
|
||||
> 该头文件中定义了一系列数据类型和结构体,包括sockaddr_in、sockaddr_in6、in_addr等类型,以及各种基本数据类型,如uint16_t、uint32_t等。这些数据类型和结构体可以帮助我们创建、表示和传递套接字地址信息,进行网络通信。
|
||||
>
|
||||
> 除此之外,netinet/in.h还定义了一些常量和枚举类型,例如IPPROTO_TCP、IPPROTO_UDP等,用于指定套接字的传输协议或其他相关参数。通过这些常量和枚举类型,我们可以更加方便地控制套接字的行为和配置。
|
||||
>
|
||||
> 总之,netinet/in.h是网络编程中一个非常重要的头文件,通过定义各种数据类型、结构体、常量和枚举类型,它为程序员提供了方便的接口,使得开发网络应用变得更加高效和简单。
|
||||
|
||||
### arpa/inet.h
|
||||
|
||||
> #include <arpa/inet.h> 是一个C语言标准库头文件,提供了一系列用于IP地址转换的函数,包括将点分十进制IP地址转换为二进制IP地址、将二进制IP地址转换为点分十进制IP地址等操作。
|
||||
>
|
||||
> 该头文件中定义了一些函数原型,包括inet_addr、inet_ntoa、inet_pton、inet_ntop等函数。其中,inet_addr函数用于将点分十进制IP地址转换为32位无符号整数;inet_ntoa函数用于将32位无符号整数表示的IP地址转换为点分十进制字符串;inet_pton函数和inet_ntop函数用于进行IPv4和IPv6地址之间的转换。
|
||||
>
|
||||
> 除此之外,<arpa/inet.h> 还定义了一些与网络字节序(big-endian)和主机字节序(little-endian)有关的函数,包括htons、htonl、ntohs、ntohl等。这些函数可以帮助我们在不同主机上正确地解析网络数据,并保证通信的正确性和可靠性。
|
||||
>
|
||||
> 总之,<arpa/inet.h> 是网络编程中一个非常重要的头文件,通过提供方便的IP地址转换函数以及网络字节序相关的函数,它使得程序员能够更加方便地处理网络通信中各种复杂的字节序和地址转换问题。
|
||||
|
||||
### unistd.h
|
||||
|
||||
> unistd.h是一个C语言标准库头文件,提供了一些UNIX系统调用相关的函数和符号常量。在Unix/Linux操作系统下,我们通常需要使用unistd.h来实现各种系统级别的操作,例如进程控制、文件IO、系统资源管理等。
|
||||
>
|
||||
> 该头文件中定义了一系列函数原型,包括read、write、close、fork、execve等函数。这些函数可以帮助我们进行文件读写操作、进程创建和替换、信号处理等操作。
|
||||
>
|
||||
> 除此之外,unistd.h还定义了一些符号常量,例如STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO等,用于表示标准输入输出文件描述符,方便程序员进行输入输出操作。同时,它还定义了一些与系统路径、进程限制、系统资源等相关的常量和变量,例如PATH_MAX、_SC_OPEN_MAX、sysconf等等。
|
||||
>
|
||||
> 总之,unistd.h是一个非常重要的头文件,在Unix/Linux编程中经常被使用。通过提供各种系统调用函数和符号常量,它为程序员提供了方便的系统级别的访问接口,使得开发更加高效和灵活。
|
||||
|
||||
### string.h
|
||||
|
||||
> string.h是一个C语言标准库头文件,提供了一系列字符串相关的函数和数据类型。在C程序中,我们通常需要使用string.h来实现各种字符串操作,如字符串拷贝、字符串比较、字符串搜索等。
|
||||
>
|
||||
> 该头文件中定义了一系列函数原型,包括strcpy、strncpy、strlen、strcmp、strncmp、strstr等函数。这些函数可以帮助我们进行字符串操作,如复制、比较、查找等等。同时,也定义了一些与内存管理相关的函数,如memset、memcpy、memmove等。
|
||||
>
|
||||
> 除此之外,string.h还定义了一些基本数据类型,例如size_t等,用于表示字符串长度等信息。
|
||||
>
|
||||
> 总之,string.h是一个非常重要的标准库头文件,在C程序中经常被使用。通过提供各种字符串操作函数和相关数据类型,它为程序员提供了方便的接口,使得开发更加高效和灵活。
|
||||
|
||||
### stdlib.h
|
||||
|
||||
> stdlib.h是一个C语言标准库头文件,提供了一些与内存分配、程序终止、随机数生成等相关的函数和数据类型。在C程序中,我们通常需要使用stdlib.h来实现各种动态内存分配、异常处理、程序退出等操作。
|
||||
>
|
||||
> 该头文件中定义了一系列函数原型,包括malloc、calloc、realloc、free等函数。这些函数可以帮助我们进行内存管理,如申请动态内存、释放动态内存等。同时,也定义了一些与异常处理相关的函数,如exit、abort等。
|
||||
>
|
||||
> 除此之外,stdlib.h还定义了一些基本数据类型,例如size_t、div_t、ldiv_t等,用于表示整数、浮点数等信息。同时,它还提供了一些随机数生成相关的函数,如rand、srand等。
|
||||
>
|
||||
> 总之,stdlib.h是一个非常重要的标准库头文件,在C程序中经常被使用。通过提供各种内存分配、异常处理和随机数生成函数以及相关数据类型,它为程序员提供了方便的接口,使得开发更加高效和灵活。
|
||||
|
||||
### fcntl.h
|
||||
|
||||
> fcntl.h是一个C语言标准库头文件,主要用于处理文件描述符。在Unix/Linux系统下,我们通常需要使用fcntl.h来实现各种文件操作,如文件锁、文件状态标志等。
|
||||
>
|
||||
> 该头文件中定义了一系列函数原型,包括fcntl、open、creat、flock等函数。这些函数可以帮助我们打开和关闭文件、控制文件状态等。此外,它还定义了一些与文件锁相关的数据类型和常量,例如flock、F_RDLCK、F_WRLCK等,用于实现文件锁定和解锁操作。
|
||||
>
|
||||
> 除此之外,fcntl.h还定义了一些与信号处理和进程控制有关的常量和函数,例如F_SETOWN、F_GETLK、sigaction等。这些常量和函数可以帮助我们实现对进程和信号的控制。
|
||||
>
|
||||
> 总之,fcntl.h是一个非常重要的头文件,在Unix/Linux编程中经常被使用。通过提供各种文件描述符相关的函数和常量、以及信号处理、进程控制等相关接口,它为程序员提供了方便的访问接口,使得开发更加高效和灵活。
|
||||
|
||||
### sys/shm.h
|
||||
|
||||
> sys/shm.h是一个C语言标准库头文件,主要用于实现共享内存操作。在Unix/Linux操作系统下,我们通常需要使用sys/shm.h来实现各种进程间的数据交换和共享内存访问。
|
||||
>
|
||||
> 该头文件中定义了一系列函数原型,包括shmget、shmat、shmdt、shmctl等函数。这些函数可以帮助我们创建共享内存区、将共享内存区附加到进程空间、解除共享内存区的附加、控制共享内存区的属性等。
|
||||
>
|
||||
> 除此之外,sys/shm.h还定义了一些与共享内存相关的结构体和常量,例如shmid_ds、SHM_RDONLY、IPC_CREAT等,用于表示共享内存的元信息和参数配置。
|
||||
>
|
||||
> 总之,sys/shm.h是一个非常重要的头文件,在Unix/Linux编程中经常被使用。通过提供各种共享内存操作函数和相关结构体,它为程序员提供了方便的接口,使得开发进程间的数据交换和共享内存访问变得更加高效和灵活。
|
||||
|
||||
### iostream
|
||||
|
||||
> iostream是一个C++标准库头文件,提供了输入输出流相关的类和函数。在C++程序中,我们通常需要使用iostream来实现各种控制台输入输出操作、文件读写操作等。
|
||||
>
|
||||
> 该头文件中定义了两个基本的C++流对象:cin和cout,分别用于从控制台读取用户输入和向控制台输出信息。除此之外,iostream还提供了一些其他的流对象和类,包括cerr、clog、ifstream、ofstream等,用于表示错误输出、日志输出、文件输入和输出等。
|
||||
>
|
||||
> 除此之外,iostream还定义了一些流操作符和流缓冲区的设置,如endl、setw等。通过这些操作符和设置,我们可以更方便地控制流的输出格式和行为。
|
||||
>
|
||||
> 总之,iostream是一个非常重要的C++标准库头文件,在C++程序中经常被使用。通过提供各种输入输出流相关的类和函数,它为程序员提供了方便的接口,使得开发控制台交互、文件读写等各种功能变得更加高效和灵活。
|
||||
@@ -0,0 +1,48 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <stdio.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/shm.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main()
|
||||
{
|
||||
// 定义客户端 sockfd 套接字描述符
|
||||
int sock_cli = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
// 定义 sockaddr_in
|
||||
struct sockaddr_in servaddr;
|
||||
memset(&servaddr, 0, sizeof(servaddr));
|
||||
servaddr.sin_family = AF_INET; // TCP/IP 协议族
|
||||
servaddr.sin_port = htons(8023); // 服务器端口
|
||||
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 服务器 ip
|
||||
|
||||
// connect 同远程服务器建立主动连接,成功时返回0,若连接失败返回-1
|
||||
if (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
|
||||
{
|
||||
perror("connect");
|
||||
exit(1);
|
||||
}
|
||||
cout << "连接服务器成功!\n";
|
||||
|
||||
char sendbuf[100]; // 发送缓冲数组
|
||||
char recvbuf[100]; // 接收缓冲数组
|
||||
while (1)
|
||||
{
|
||||
memset(sendbuf, 0, sizeof(sendbuf));
|
||||
cin >> sendbuf; // 向发送缓冲数组写入数据
|
||||
send(sock_cli, sendbuf, sizeof(sendbuf), 0); // 发送数据
|
||||
if (strcmp(sendbuf, "exit") == 0)
|
||||
break; // 如果发送字符为exit,则跳出发送循环
|
||||
}
|
||||
|
||||
close(sock_cli); // 关闭发送套接字描述符
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <stdio.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/shm.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main()
|
||||
{
|
||||
// 定义服务端 sockfd (套接字描述符)
|
||||
int server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
// 定义服务端套接字 sockaddr_in (套接字地址结构)
|
||||
struct sockaddr_in server_sockaddr;
|
||||
server_sockaddr.sin_family = AF_INET; // TCP/IP 协议族
|
||||
server_sockaddr.sin_port = htons(8023); // 端口号
|
||||
server_sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // ip 地址,127.0.0.1 是回环地址,相当于本机 ip
|
||||
|
||||
// bind (功能:为套接字绑定地址), 绑定成功返回 0 ,绑定出错返回 -1
|
||||
if (bind(server_sockfd, (struct sockaddr *)&server_sockaddr, sizeof(server_sockaddr)) == -1)
|
||||
{
|
||||
perror("bind"); // 输出错误原因
|
||||
exit(1); // 结束程序
|
||||
}
|
||||
|
||||
// listen (将一个套接字置为监听模式,准备接收传入连接。用于服务器,指明某个套接字连接是被动的监听状态)
|
||||
// 成功返回 0 ,出错返回 -1
|
||||
if (listen(server_sockfd, 20) == -1)
|
||||
{
|
||||
perror("listen"); // 输出错误原因
|
||||
exit(1); // 结束程序
|
||||
}
|
||||
|
||||
// 客户端套接字
|
||||
struct sockaddr_in client_addr;
|
||||
socklen_t length = sizeof(client_addr);
|
||||
|
||||
// accept (功能:从已完成连接队列中取出成功建立连接的套接字,返回成功连接的套接字描述符)
|
||||
// 成功返回非负描述符,出错返回 -1
|
||||
int conn = accept(server_sockfd, (struct sockaddr *)&client_addr, &length);
|
||||
if (conn < 0)
|
||||
{
|
||||
perror("connect"); // 输出错误原因
|
||||
exit(1); // 结束程序
|
||||
}
|
||||
cout << "客户端成功连接\n";
|
||||
|
||||
// 接收缓冲区:定义为 1000 字节大小,最多存储 999 个字符长度的字符串,最后一个字符要留给'\0'
|
||||
char buffer[1000];
|
||||
|
||||
// 不断接收数据
|
||||
while (1)
|
||||
{
|
||||
// memset函数有三个参数:第一个参数是要被初始化的内存区域的起始地址,第二个参数是要设置的值,第三个参数是要初始化的字节数
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
// recv (功能:接收数据,返回实际接收的数据长度,出错时返回-1)
|
||||
int len = recv(conn, buffer, sizeof(buffer), 0);
|
||||
// 客户端发送 exit 或者异常结束时,退出
|
||||
if (strcmp(buffer, "exit") == 0 || len <= 0)
|
||||
break;
|
||||
cout << "收到客户端信息:" << buffer << endl;
|
||||
}
|
||||
|
||||
// 套接字通常需要在完成数据传输等操作后及时关闭,以释放系统资源并避免出现一些问题,比如资源耗尽、端口占用等
|
||||
// conn和server_sockfd分别表示客户端和服务器端的套接字文件描述符,通过调用close函数来关闭它们
|
||||
close(conn); // 关闭数据接受描述符
|
||||
close(server_sockfd); // 关闭套接字
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user