C/C++中的Socket编程
在当今世界,计算机网络在数据传输领域发挥着重要作用。这是一个每个程序员都应该了解的课题。在计算机网络下,套接字编程是编程世界中最重要的主题之一。在这个话题中,我们将讨论套接字编程和在C++中实现的套接字编程的不同方法。
在C++中,套接字编程是一种通过网络将两个或更多的节点相互结合起来的方法,这样节点就可以共享数据而不会有任何数据损失。在这种连接中,一个节点监听一个端口,该端口连接到一个特定的IP地址。当客户端到达服务器时,服务器会创建套接字监听器。
什么是套接字?
让我们通过谈论实时的例子来了解套接字。套接字是一种在两个设备之间提供连接的媒介类型。Socket可以是提供Socket和手机之间连接的手机充电器,也可以是手机和笔记本电脑。在Socket的帮助下,不同的应用程序通过不同的端口连接到本地网络。每次创建Socket时,服务器指定程序,而该程序指定Socket和域名地址。
套接字是一种机制,用于在不同的进程之间交换数据。在这里,这些进程或者存在于不同的设备中,或者存在于通过网络连接的同一设备中。一旦创建了套接字的连接,那么数据就可以双向发送,一直持续到其中一个端点关闭连接。
客户-服务器通信中的程序
我们必须遵循一些程序来建立客户-服务器通信。这些程序如下。
- 套接字: 在套接字的帮助下,我们可以创建一个新的通信。
- 绑定: 在此帮助下,我们可以将本地地址与套接字相连。
- 监听: 在此帮助下,我们可以接受连接。
- 接受: 在这个帮助下,我们可以阻止传入的连接,直到请求到达。
- 连接: 在这个帮助下,我们可以尝试建立连接。
- 发送: 在此帮助下,我们可以在网络上发送数据。
- 接收 :在这个帮助下,我们可以在网络上接收数据。
- 关闭 :在此帮助下,我们可以从网络上释放连接。
创建服务器Socket的阶段
有一些阶段,我们可以为服务器创建套接字。这些阶段如下。
- int socketcr: Socket(domain, type, protocol)
- Socketcr: 它是一个整数类型,它就像一个文件处理程序。
- Domain: 它是一个通信域,它是一个整数类型。
- Type: 它是一个通信类型。
- SOCK_DGRAM: 它是UDP的一种类型,是不可靠的和无连接的。
- 协议: 它用于分配IP地址的协议值,它是0。协议值类似于出现在口袋的IP头的协议字段中的值。
什么是连接?
连接是两台机器之间的一种关系,在这种关系中,两个软件彼此都知道对方。这两个软件知道如何与对方建立连接;换句话说,我们可以说,这两个软件知道如何在网络上发送比特。套接字的连接意味着这两台机器应该知道彼此之间的所有信息,如电话号码、IP地址和TCP端口。
套接字是一种类型的对象,它类似于文件,允许程序接受传入的连接,并允许他们发送或接收传入的连接。同时,它也是分配给服务器进程的一种资源类型。
服务器可以在socket()的帮助下创建一个套接字。这个套接字不能与任何其他处理器共享。
- Setsockopt: 在Setsockopt的帮助下,我们可以操作套接字的各种选项,这些选项是由套接字的文件描述符所指的。这个过程是完全可选的。在Setsockopt的帮助下,我们可以重新使用客户和服务器的端口和地址。当服务器出现 “地址已被使用 “的错误时,我们可以通过Setsockopt的帮助来防止它。
- 绑定: 我们可以在绑定函数的帮助下用地址和端口来绑定套接字。这个操作是在创建套接字后进行的。例如,如果我们试图将服务器与本地主机绑定,那么我们使用INADDR_ANY来定义服务器的IP地址。
- 监听: 我们可以在监听()函数的帮助下建立一个连接模式的套接字。连接模式套接字的一个例子是SOCK_STREAM。这可以通过socket参数来定义。它用于接受传入的连接,对传入的连接进行排队操作,并对传入的连接进行积压。当一个传入的连接请求服务器确认时,套接字被放入被动模式。服务器的积压参数指的是它不能允许一次有一个以上的连接到服务器。如果一些传入的连接已经来了,而队列已经满了,那么服务器就会提供错误的指示,即 “ECONNREFUSED”。在listen()的帮助下,传入的连接被搁置,当队列为空时,它调用所有传入的连接到服务器上。
- 接受: 在accept()系统调用的帮助下,我们可以制作基于连接的套接字。一些基于连接的套接字是SOCK_STREAM和SOCK_SEQPACKET。它提取所有首先进入的连接,并允许他们的请求进入服务器。新连接的列表在创建新套接字的另一个参数的帮助下是无法监听的。
客户端的阶段
- 套接字连接: 这与创建服务器的方法完全相同。
- 连接: 我们可以在connect()系统调用的帮助下启动对套接字的连接。如果套接字的参数是SOCK_DGRAM类型,那么我们可以在connect()的帮助下将数据报定义为永久性的。如果套接字是SOCK_STREAM类型的,那么我们可以尝试为服务器建立另一个连接。在connect()函数的帮助下,我们也可以为外国协会创建一个连接。如果套接字没有被绑定,那么系统会给本地关联分配唯一值。当系统成功调用完成后,套接字就可以发送或接收任何类型的数据了。
- 发送/接收: send()和recv()函数可以执行以下操作。
- 套接字可以在其上进行数据的相互通信。
- 存储缓冲区可以存储有关地址的数据,如addr_of_data和addr_of_buffer。
- 它处理缓冲区的大小,如len_of_data和len_of_buffer。
- 它处理的是说明数据将如何发送的标志。
在Socket中建立连接的步骤
它在不同的客户和服务器之间建立了一个连接。但客户端和服务器都可以处理套接字连接。每个进程都要为自己的套接字建立一个连接。
在客户端建立一个套接字的步骤如下。
- 它在socket()系统调用的帮助下创建一个套接字。
- 然后,我们必须在system()调用的帮助下,与服务器的套接字地址连接。
- 然后,我们必须发送和接收数据。我们可以通过不同的方式来完成这个任务。我们可以通过read()和write()函数来完成。
在服务器端建立一个套接字的步骤如下。
- 它首先在socket()系统调用的帮助下创建一个套接字。
- 然后,在bind()系统调用的帮助下,将套接字绑定到一个地址。一个地址由主机中的服务器套接字的端口号组成。
- 然后在listen()系统调用的帮助下监听连接。
- 然后,服务器在accept()系统调用的帮助下接受进入的连接。它也会阻止所有传入的命令,直到客户端连接到服务器。
- 然后开始发送和接收数据的过程。
在没有多线程的情况下连接多个客户端
在各种例子中,我们看到单个用户如何与服务器连接。在今天的编程世界里,多个用户用不同的套接字连接到服务器上。
有各种方法来实现这一点。其中之一就是多线程。在多线程的帮助下,我们可以实现这一点。我们可以在select()函数的帮助下实现一个多线程过程。
例子。
客户端的代码。
// Client side C/C++ program to demonstrate Socket
// programming
#include
#include
#include
#include
#include
#define PORT 8080
int main(int argc, char const* argv[])
{
int sock = 0, valread, client_fd;
struct sockaddr_in serv_addr;
char* hello = "Hello from client";
char buffer[1024] = { 0 };
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("\n Socket creation error \n");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// Convert IPv4 and IPv6 addresses from text to binary
// form
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)
<= 0) {
printf(
"\nInvalid address/ Address not supported \n");
return -1;
}
if ((client_fd
= connect(sock, (struct sockaddr*)&serv_addr,
sizeof(serv_addr)))
< 0) {
printf("\nConnection Failed \n");
return -1;
}
send(sock, hello, strlen(hello), 0);
printf("Hello message sent\n");
valread = read(sock, buffer, 1024);
printf("%s\n", buffer);
// closing the connected socket
close(client_fd);
return 0;
}
Code for server:
// Server side C/C++ program to demonstrate Socket
// programming
#include
#include
#include
#include
#include
#include
#define PORT 8080
int main(int argc, char const* argv[])
{
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1024] = { 0 };
char* hello = "Hello from server";
// Creating socket file descriptor
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// Forcefully attaching socket to port 8080
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 = INADDR_ANY;
address.sin_port = htons(PORT);
// Forcefully attaching socket to port 8080
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);
}
valread = read(new_socket, buffer, 1024);
printf("%s\n", buffer);
send(new_socket, hello, strlen(hello), 0);
printf("Hello message sent\n");
// closing the connected socket
close(new_socket);
// closing the listening socket
shutdown(server_fd, SHUT_RDWR);
return 0;
}
编译。
输出。
Socket编程的用途
Socket程序被用来在不同的进程之间进行通信,通常运行在不同的系统上。它主要用于创建一个客户-服务器环境。本帖提供了用于创建服务器和客户端程序的各种功能以及一个示例程序。
在这个例子中,客户程序向服务器发送一个文件名,而服务器则将文件的内容发回给客户。套接字编程通常与基本通信协议有关,如TCP/UDP和ICMP等原始套接字。与HTTP/DHCP/SMTP等底层协议相比,这些协议的通信开销很小。
客户端和服务器之间的一些基本数据通信是。
- 文件传输。发送名称并获得一个文件。
- 网页。发送URL并获得一个页面。
- 回音。发送一个信息并得到它的反馈。
缺点
- C++只能与被请求的机器建立通信,而不能与网络上的任何其他机器建立通信。
- 套接字只允许发送原始数据。这意味着客户端和服务器需要机制来解释数据。