在计算机领域中,Socket(套接字)是一种用于网络通信的编程接口,它可以在不同的计算机之间传输数据。而Linux系统作为一个广泛应用的操作系统,也用Socket来处理网络通信。但在实际应用中,如何读取Socket数据却是一个让人头疼的问题。本文将带领读者探索Linux读取Socket的技巧和方法,帮助您更加顺畅地进行Socket通信。
成都创新互联专注于企业网络营销推广、网站重做改版、迁安网站定制设计、自适应品牌网站建设、H5响应式网站、成都商城网站开发、集团公司官网建设、成都外贸网站建设公司、高端网站制作、响应式网页设计等建站业务,价格优惠性价比高,为迁安等各大城市提供网站开发制作服务。
一、非阻塞式Socket的优势
在Linux Socket编程中,程序默认使用的是阻塞式Socket,这意味着当Socket处于等待状态时,程序会一直阻塞等待,直到数据准备好进行传输为止。这种模式虽然比较简单,但是随着数据量的增多,程序的性能将会受到严重影响。
相对来说,非阻塞式Socket的优势更加明显。在非阻塞式Socket模式下,程序在等待数据传输时并不会一直阻塞等待,而是会继续执行其他任务,再通过轮询方式来检查Socket数据是否准备好进行传输。当数据准备好时,程序会立即读取数据,而无需等待。
二、使用select函数实现非阻塞式Socket
在Linux系统中,可以使用select函数来实现非阻塞式Socket。该函数可以同时检测多个文件描述符的状态,当文件描述符的状态发生变化时,select函数会返回调用者更改的文件描述符的状态。这种方式可以有效地减少程序的阻塞等待时间,提高程序性能。
下面是使用select函数实现非阻塞式Socket的示例代码:
“`c
fd_set rfds;
struct timeval tv;
int retval;
FD_ZERO(&rfds);
FD_SET(sockfd, &rfds);
tv.tv_sec = 2;
tv.tv_usec = 0;
retval = select(sockfd+1, &rfds, NULL, NULL, &tv);
if(retval == -1){
perror(“select()”);
}
else if (retval == 0){
printf(“Timeout occurred! No data after 2 seconds.\n”);
}
else{
if(FD_ISSET(0, &rfds)){
printf(“Data is avlable now.\n”);
}
}
“`
在上述代码中,FD_ZERO和FD_SET函数用于初始化和向文件描述符集中添加Socket文件描述符。然后,我们设置了监视等待时间为2秒。如果监视到的文件描述符中有文件描述符可以读取,则select函数会返回1,程序会读取该文件描述符中的数据。
三、使用epoll函数实现非阻塞式Socket
epoll是Linux系统提供的另一种高效的I/O多路复用机制,相比于select函数,它具有更优秀的性能和更多的高级功能,可以大大提高程序的并发能力和运行效率。
下面是使用epoll函数实现非阻塞式Socket的示例代码:
“`c
#include
…
#define MAX_EVENTS 10
struct epoll_event ev, events[MAX_EVENTS];
int listen_sock, conn_sock, nfds, epollfd;
listen_sock = create_and_bind_socket(port);
make_socket_non_blocking(listen_sock);
epollfd = epoll_create1(0);
if (epollfd == -1){
perror(“epoll_create1”);
exit(EXIT_FLURE);
}
ev.events = EPOLLIN;
ev.data.fd = listen_sock;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1){
perror(“epoll_ctl: listen_sock”);
exit(EXIT_FLURE);
}
while(1){
nfds = epoll_wt(epollfd, events, MAX_EVENTS, -1);
if (nfds == -1){
perror(“epoll_wt”);
exit(EXIT_FLURE);
}
for (int n = 0; n
if (events[n].data.fd == listen_sock){
conn_sock = accept(listen_sock, (struct sockaddr *) &peer_addr,
&peer_addr_size);
if (conn_sock == -1){
perror(“accept”);
exit(EXIT_FLURE);
}
make_socket_non_blocking(conn_sock);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = conn_sock;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1){
perror(“epoll_ctl: conn_sock”);
exit(EXIT_FLURE);
}
}
else{
do_use_fd(events[n].data.fd);
}
}
}
…
“`
在上述代码中,我们首先创建了一个监听套接字,并将其添加到epoll事件监视器中。然后,通过epoll_wt函数等待事件的发生。当事件发生时,我们将进行遍历,并处理到达的事件。具体的处理方式可以根据需要自行实现。
四、结合多线程实现高并发Socket读取
对于大型网络应用程序来说,使用多线程来处理Socket读取任务也是非常可行的一种解决方案。通过将读取Socket的任务分配给多个线程来处理,可以有效提高应用程序的读取效率。
下面是一个简单的示例代码,演示如何使用多线程实现高并发Socket读取:
“`c
#include
void *socket_handler(void *socket_desc){
int socket = *(int*)socket_desc;
int read_size;
char client_message[2023];
while( (read_size = recv(socket , client_message , 2023 , 0)) > 0 ){
write(socket , client_message , strlen(client_message));
}
if(read_size == 0){
puts(“Client disconnected”);
fflush(stdout);
}
else if(read_size == -1){
perror(“recv fled”);
}
free(socket_desc);
return 0;
}
…
while(1){
new_socket = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c);
if (new_socket
perror(“accept fled”);
return 1;
}
pthread_t sniffer_thread;
int *new_sock = malloc(sizeof(int));
*new_sock = new_socket;
if( pthread_create( &sniffer_thread , NULL , socket_handler , (void*) new_sock)
perror(“could not create thread”);
return 1;
}
}
“`
在上述代码中,我们创建了一个socket_handler线程,并将分配给该线程的Socket连接作为参数传入。然后,在线程中读取Socket连接的数据并进行处理。通过使用多线程,可以实现高并发的Socket读取任务,提高整个应用程序的效率。
相关问题拓展阅读:
要下班了,时间急,不写代码了先给你一个思路
实现最简单的udp socket 模型,实现发送一个字符串。
实现一个简单的打开文件,读取文件的例子,如用fgets(),类似的函数有很多,然后再把读取的培虚文件内容忘另一个文件里写(相关函数fopen(),write(),read())。
把上面两个函数结合到一起者族,在客户端实现打开要传送的文件,按一定的大小读取,读取后调用sendto()发送到服务器端。在服务器端创建一个文件,然后调用recvfrom()接受客户端发送过来的数据,向来是创建的那个文件中写。
下面是改好的udp发送文件的例子。
服务器端程序的编译
gcc -o file_server file_server
客户端程序的编译
gcc -o file_client file_client.c
服务器程序和客户端程应当分别运行在2台计算机上.
服务器端程序的运行,在一个计算机的终端执行
./file_server
客户端程序的运行,在另一个计算机的终端中执行
./file_client 运行服务器程序的计算机的IP地址
根据提示输入要传输的服务器上的文件,该文件在服务器的运行目录上
在实际编程和测试中,可以用2个终端代替2个计算机,这样就可以在一台计算机上测试网络程序,
服务器端程序的运行,在一个终端执行
./file_server
客户端程序的运行,在另一个终端中执行
./file_client 127.0.0.1
说明: 任何计算机都可以通过127.0.0.1访问自己. 也可以用计算机的实际IP地址代替127.0.0.1
//////////////////////////////////////////////////////////////////////////////////////
// file_server.c 文件传输顺序服务器示例
//////////////////////////////////////////////////////////////////////////////////////
//本文件是服务器的代码
#include // for sockaddr_in
#include // for socket
#include // for socket
#include// for printf
#include// for exit
#include// for bzero
/*
#include
#include
#include
#include
*/
#define HELLO_WORLD_SERVER_PORT
#define LENGTH_OF_LISTEN_QUEUE 20
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
int main(int argc, char **argv)
{
//设置一个socket地址结构server_addr,代表服务器internet地址, 端口
struct sockaddr_in server_addr, pcliaddr;
bzero(&server_addr,sizeof(server_addr)); //把一段内存区的内容全部设置为0
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
//创建用于internet的据报套接字(UDPt,用server_socket代表服务器socket
// 创建数据报套接字(UDP)
int server_socket = socket(PF_INET,SOCK_DGRAM,0);
if( server_socket FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(buffer));
//int fp = open(file_name, O_RDON);
//if( fp 0)
while( (file_block_length = fread(buffer,sizeof(char),BUFFER_SIZE,fp))>0)
{
printf(“file_block_length = %d\n”,file_block_length);
//发送buffer中的字符串到new_server_socket,实际是给客户端
if(send(new_server_socket,buffer,file_block_length,0) // for sockaddr_in
#include // for socket
#include // for socket
#include// for printf
#include// for exit
#include// for bzero
/*
#include
#include
#include
#include
*/
#define HELLO_WORLD_SERVER_PORT
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
int main(int argc, char **argv)
{
if (argc != 2)
{
printf(“Usage: ./%s ServerIPAddress\n”,argv);
exit(1);
}
//设置一个socket地址结构client_addr,代表客户机internet地址, 端口
struct sockaddr_in client_addr;
bzero(&client_addr,sizeof(client_addr)); //把一段内存区的内容全部设置为0
client_addr.sin_family = AF_INET; //internet协议族
client_addr.sin_addr.s_addr = htons(INADDR_ANY);//INADDR_ANY表示自动获取本机地址
client_addr.sin_port = htons(0); //0表示让系统自动分配一个空闲端口
//创建用于internet的流协议(TCP)socket,用client_socket代表客户机socket
int client_socket = socket(AF_INET,SOCK_DGRAM,0);
if( client_socket BUFFER_SIZE?BUFFER_SIZE:strlen(file_name));
//向服务器发送buffer中的数据
socklen_t n = sizeof(server_addr) ;
sendto(client_socket,buffer,BUFFER_SIZE,0,(struct sockaddr*)&server_addr,n);
// int fp = open(file_name, O_WRON|O_CREAT);
// if( fp
FILE * fp = fopen(file_name,”w”);
if(NULL == fp )
{
printf(“File:\t%s Can Not Open To Write\n”, file_name);
exit(1);
}
//从服务器接收数据到buffer中
bzero(buffer,BUFFER_SIZE);
int length = 0;
while( length = recv(client_socket,buffer,BUFFER_SIZE,0))
{
if(length
{
printf(“Recieve Data From Server %s Failed!\n”, argv);
break;
}
//int write_length = write(fp, buffer,length);
int write_length = fwrite(buffer,sizeof(char),length,fp);
if (write_length
{
printf(“File:\t%s Write Failed\n”, file_name);
break;
}
bzero(buffer,BUFFER_SIZE);
}
printf(“Recieve File:\t %s From Server Finished\n”,file_name, argv);
return 0;
}
请采纳。
如果你的客户端在发送文件时,每次都重新connect,再神租进行数据传输,则你的程序无法解决数据的区分。
如果客户端是一次connect循环发送,后台服务循环接收,则
(1)如果你的服务端只有一个进程(不支持并发),则A和B不会同时运行,只能按顺序接收游激兆完铅闷A再接收B
(2)如果,每一个新链接上来,你都建立一个新的进程去工作,则不会有问题。
对每个客户端请求,服务端守护进程fork子进程
成都创新互联科技有限公司,是一家专注于互联网、IDC服务、应用软件开发、网站建设推广的公司,为客户提供互联网基础服务!
创新互联(www.cdcxhl.com)提供简单好用,价格厚道的香港/美国云服务器和独立服务器。创新互联——四川成都IDC机房服务器托管/机柜租用。为您精选优质idc数据中心机房租用、服务器托管、机柜租赁、大带宽租用,高电服务器托管,算力服务器租用,可选线路电信、移动、联通机房等。
标题名称:Linux读取Socket技巧大揭秘(linuxreadsocket)
当前链接:http://www.shufengxianlan.com/qtweb/news26/262776.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联