日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux如何实现网络高级编程,嵌入式Linux网络编程之:网络高级编程-嵌入式系统-与非网...

發布時間:2023/12/4 linux 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux如何实现网络高级编程,嵌入式Linux网络编程之:网络高级编程-嵌入式系统-与非网... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

10.3??網絡高級編程

在實際情況中,人們往往遇到多個客戶端連接服務器端的情況。由于之前介紹的如connet()、recv()和send()等都是阻塞性函數,如果資源沒有準備好,則調用該函數的進程將進入睡眠狀態,這樣就無法處理I/O多路復用的情況了。本節給出了兩種解決I/O多路復用的解決方法,這兩個函數都是之前學過的fcntl()和select()(請讀者先復習第6章中的相關內容)。可以看到,由于在Linux中把socket也作為一種特殊文件描述符,這給用戶的處理帶來了很大的方便。

1.fcntl()

函數fcntl()針對socket編程提供了如下的編程特性。

n 非阻塞I/O:可將cmd設置為F_SETFL,將lock設置為O_NONBLOCK。

n 異步I/O:可將cmd設置為F_SETFL,將lock設置為O_ASYNC。

下面是用fcntl()將套接字設置為非阻塞I/O的實例代碼:

/*?net_fcntl.c?*/

#include?

#include?

#include?

#include?

#include?

#include?

#include?

#include?

#include?

#include?

#include?

#include?

#include?

#define?PORT??????????????????1234

#define?MAX_QUE_CONN_NM????????5

#define?BUFFER_SIZE?????????????1024

int?main()

{

struct?sockaddr_in?server_sockaddr,?client_sockaddr;

int?sin_size,?recvbytes,?flags;

int?sockfd,?client_fd;

char?buf[BUFFER_SIZE];

if?((sockfd?=?socket(AF_INET,?SOCK_STREAM,?0))?==?-1)

{

perror("socket");

exit(1);

}

server_sockaddr.sin_family?=?AF_INET;

server_sockaddr.sin_port?=?htons(PORT);

server_sockaddr.sin_addr.s_addr?=?INADDR_ANY;

bzero(&(server_sockaddr.sin_zero),?8);

int?i?=?1;/*?允許重復使用本地地址與套接字進行綁定?*/

setsockopt(sockfd,?SOL_SOCKET,?SO_REUSEADDR,?&i,?sizeof(i));

if?(bind(sockfd,?(struct?sockaddr?*)&server_sockaddr,

sizeof(struct?sockaddr))?==?-1)

{

perror("bind");

exit(1);

}

if(listen(sockfd,MAX_QUE_CONN_NM)?==?-1)

{

perror("listen");

exit(1);

}

printf("Listening....\n");

/*?調用fcntl()函數給套接字設置非阻塞屬性?*/

flags?=?fcntl(sockfd,?F_GETFL);

if?(flags?

{

perror("fcntl");

exit(1);

}

while(1)

{

sin_size?=?sizeof(struct?sockaddr_in);

if?((client_fd?=?accept(sockfd,

(struct?sockaddr*)&client_sockaddr,?&sin_size))?

{

perror("accept");

exit(1);

}

if?((recvbytes?=?recv(client_fd,?buf,?BUFFER_SIZE,?0))?

{

perror("recv");

exit(1);

}

printf("Received?a?message:?%s\n",?buf);

}?/*while*/

close(client_fd);

exit(1);

}

運行該程序,結果如下所示:

$?./net_fcntl

Listening....

accept:?Resource?temporarily?unavailable

可以看到,當accept()的資源不可用(沒有任何未處理的等待連接的請求)時,程序就會自動返回。

2.select()

使用fcntl()函數雖然可以實現非阻塞I/O或信號驅動I/O,但在實際使用時往往會對資源是否準備完畢進行循環測試,這樣就大大增加了不必要的CPU資源的占用。在這里可以使用select()函數來解決這個問題,同時,使用select()函數還可以設置等待的時間,可以說功能更加強大。下面是使用select()函數的服務器端源代碼。客戶端程序基本上與10.2.3小節中的例子相同,僅加入一行sleep()函數,使得客戶端進程等待幾秒鐘才結束。

/*?net_select.c?*/

#include?

#include?

#include?

#include?

#include?

#include?

#include?

#include?

#include?

#define?PORT?????????????????4321

#define?MAX_QUE_CONN_NM???????5

#define?MAX_SOCK_FD????????????FD_SETSIZE

#define?BUFFER_SIZE????????????1024

int?main()

{

struct?sockaddr_in?server_sockaddr,?client_sockaddr;

int?sin_size,?count;

fd_set?inset,?tmp_inset;

int?sockfd,?client_fd,?fd;

char?buf[BUFFER_SIZE];

if?((sockfd?=?socket(AF_INET,?SOCK_STREAM,?0))?==?-1)

{

perror("socket");

exit(1);

}

server_sockaddr.sin_family?=?AF_INET;

server_sockaddr.sin_port?=?htons(PORT);

server_sockaddr.sin_addr.s_addr?=?INADDR_ANY;

bzero(&(server_sockaddr.sin_zero),?8);

int?i?=?1;/*?允許重復使用本地地址與套接字進行綁定?*/

setsockopt(sockfd,?SOL_SOCKET,?SO_REUSEADDR,?&i,?sizeof(i));

if?(bind(sockfd,?(struct?sockaddr?*)&server_sockaddr,

sizeof(struct?sockaddr))?==?-1)

{

perror("bind");

exit(1);

}

if(listen(sockfd,?MAX_QUE_CONN_NM)?==?-1)

{

perror("listen");

exit(1);

}

printf("listening....\n");

/*將調用socket()函數的描述符作為文件描述符*/

FD_ZERO(&inset);

FD_SET(sockfd,?&inset);

while(1)

{

tmp_inset?=?inset;

sin_size=sizeof(struct?sockaddr_in);

memset(buf,?0,?sizeof(buf));

/*調用select()函數*/

if?(!(select(MAX_SOCK_FD,?&tmp_inset,?NULL,?NULL,?NULL)?>?0))

{

perror("select");

}

for?(fd?=?0;?fd?

{

if?(FD_ISSET(fd,?&tmp_inset)?>?0)

{

if?(fd?==?sockfd)

{?/*?服務端接收客戶端的連接請求?*/

if?((client_fd?=?accept(sockfd,

(struct?sockaddr?*)&client_sockaddr,?&sin_size))==?-1)

{

perror("accept");

exit(1);

}

FD_SET(client_fd,?&inset);

printf("New?connection?from?%d(socket)\n",?client_fd);

}

else?/*?處理從客戶端發來的消息?*/

{

if?((count?=?recv(client_fd,?buf,?BUFFER_SIZE,?0))?>?0)

{

printf("Received?a?message?from?%d:?%s\n",

client_fd,?buf);

}

else

{

close(fd);

FD_CLR(fd,?&inset);

printf("Client?%d(socket)?has?left\n",?fd);

}

}

}?/*?end?of?if?FD_ISSET*/

}?/*?end?of?for?fd*/

}?/*?end?if?while?while*/

close(sockfd);

exit(0);

}

運行該程序時,可以先啟動服務器端,再反復運行客戶端程序(這里啟動兩個客戶端進程)即可,服務器端運行結果如下所示:

$?./server

listening....

New?connection?from?4(socket)?????????????????/*?接受第一個客戶端的連接請求*/

Received?a?message?from?4:?Hello,First!????/*?接收第一個客戶端發送的數據*/

New?connection?from?5(socket)??????????????/*?接受第二個客戶端的連接請求*/

Received?a?message?from?5:?Hello,Second!???/*?接收第二個客戶端發送的數據*/

Client?4(socket)?has?left???????????????????/*?檢測到第一個客戶端離線了*/

Client?5(socket)?has?left???????????????????/*?檢測到第二個客戶端離線了*/

$?./client?localhost?Hello,First!?&?./client?localhost?Hello,Second

總結

以上是生活随笔為你收集整理的linux如何实现网络高级编程,嵌入式Linux网络编程之:网络高级编程-嵌入式系统-与非网...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。