在C语言中,阻塞网络编程是一种常见的编程方式,它使得程序在执行某些操作时会暂停执行,直到特定条件满足或事件发生,以下是对C语言中阻塞网络编程的详细解释:
阻塞网络编程的基本概念
阻塞网络编程指的是程序在执行网络I/O操作(如读取数据、发送数据等)时,如果所需条件不满足(如数据未到达、连接未建立等),程序会暂停执行,等待条件满足后再继续执行,这种编程方式在某些场景下非常直观和易于理解,但也可能因为长时间等待而导致程序效率低下。
常见的阻塞函数
1、sleep()函数:使程序暂停执行一段时间,单位为秒。sleep(5);
会使程序暂停执行5秒。
2、read()函数:从文件或输入设备读取数据,当没有数据可读时,程序将阻塞在此处等待数据准备就绪。
3、write()函数:将数据写入文件或输出设备,如果写入的数据无法立即处理,程序将阻塞在此处等待直到数据处理完成。
4、accept()函数:用于接受传入的网络连接请求,如果没有新的连接请求到达,则程序将阻塞在此处等待新的连接请求。
5、recv()函数:用于从网络套接字接收数据,如果没有数据可接收,则程序将阻塞在此处等待数据到达。
阻塞网络编程的示例代码
以下是一个使用阻塞方式进行网络通信的简单示例,展示了客户端如何连接到服务器并发送/接收数据:
服务器端代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #define PORT 8080 int main() { int server_fd, new_socket; struct sockaddr_in address; int opt = 1; int addrlen = sizeof(address); char buffer[1024] = {0}; char hello = "Hello from server"; // 创建socket文件描述符 if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("socket failed"); exit(EXIT_FAILURE); } // 强制附加socket到端口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); // 绑定socket到端口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); } read(new_socket, buffer, 1024); printf("%s ",buffer ); send(new_socket , hello , strlen(hello) , 0 ); printf("Hello message sent "); return 0; }
客户端代码
#include <stdio.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> #define PORT 8080 int main(int argc, char const argv[]) { struct sockaddr_in serv_addr; int sock = 0; char hello = "Hello from client"; char buffer[1024] = {0}; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf(" Socket creation error "); return -1; } serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(PORT); if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0) { printf(" Invalid address/ Address not supported "); return -1; } if (connect(sock, (struct sockaddr )&serv_addr, sizeof(serv_addr)) < 0) { printf(" Connection Failed "); return -1; } send(sock , hello , strlen(hello) , 0 ); printf("Hello message sent "); read(sock , buffer, 1024); printf("%s ",buffer ); return 0; }
在这个示例中,服务器端首先创建一个socket,然后绑定到本地地址和端口上,并开始监听客户端的连接请求,当有客户端连接时,服务器接受连接并接收客户端发送的数据,然后发送响应给客户端,客户端则创建一个socket,连接到服务器,并发送数据给服务器,然后接收服务器的响应。
阻塞与非阻塞的区别
1、阻塞模式:在阻塞模式下,调用某个函数(如recv()
)后,如果数据没有立即可用,函数不会返回,整个进程会被挂起,直到数据到来或者发生错误,这种方式简化了编程模型,因为不需要额外处理异步事件通知和数据缓冲。
2、非阻塞模式:在非阻塞模式下,即使没有数据可读或可写,函数也会立即返回,不会阻塞进程的执行,这要求程序员必须检查返回值以确定操作是否成功,并在适当的时候重试操作,非阻塞模式适用于需要高并发处理大量网络连接的场景,因为它允许单个线程或进程同时管理多个连接,而不必为每个连接分配一个线程。
FAQs
Q1: 阻塞网络编程中,如何避免死锁问题?
A1: 在阻塞网络编程中,为了避免死锁问题,应确保正确地使用同步机制(如互斥锁、条件变量等),避免循环等待资源的情况发生,还可以通过设置超时时间、使用非阻塞I/O等方式来减少死锁的风险。
Q2: 阻塞网络编程与非阻塞网络编程相比,有哪些优缺点?
A2: 阻塞网络编程的优点在于编程模型简单直观,易于理解和实现,它的缺点是在处理大量并发连接时效率较低,因为每个连接都需要占用一个线程或进程资源,相比之下,非阻塞网络编程虽然编程模型相对复杂,但能够更有效地利用系统资源,提高并发处理能力。
原创文章,作者:未希,如若转载,请注明出处:https://www.kdun.com/ask/1608663.html
本网站发布或转载的文章及图片均来自网络,其原创性以及文中表达的观点和判断不代表本网站。如有问题,请联系客服处理。
发表回复