linux如何实现网络高级编程,嵌入式Linux网络编程之:网络高级编程-嵌入式系统-与非网...
10.3??網(wǎng)絡(luò)高級編程
在實(shí)際情況中,人們往往遇到多個客戶端連接服務(wù)器端的情況。由于之前介紹的如connet()、recv()和send()等都是阻塞性函數(shù),如果資源沒有準(zhǔn)備好,則調(diào)用該函數(shù)的進(jìn)程將進(jìn)入睡眠狀態(tài),這樣就無法處理I/O多路復(fù)用的情況了。本節(jié)給出了兩種解決I/O多路復(fù)用的解決方法,這兩個函數(shù)都是之前學(xué)過的fcntl()和select()(請讀者先復(fù)習(xí)第6章中的相關(guān)內(nèi)容)??梢钥吹?#xff0c;由于在Linux中把socket也作為一種特殊文件描述符,這給用戶的處理帶來了很大的方便。
1.fcntl()
函數(shù)fcntl()針對socket編程提供了如下的編程特性。
n 非阻塞I/O:可將cmd設(shè)置為F_SETFL,將lock設(shè)置為O_NONBLOCK。
n 異步I/O:可將cmd設(shè)置為F_SETFL,將lock設(shè)置為O_ASYNC。
下面是用fcntl()將套接字設(shè)置為非阻塞I/O的實(shí)例代碼:
/*?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;/*?允許重復(fù)使用本地地址與套接字進(jìn)行綁定?*/
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");
/*?調(diào)用fcntl()函數(shù)給套接字設(shè)置非阻塞屬性?*/
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);
}
運(yùn)行該程序,結(jié)果如下所示:
$?./net_fcntl
Listening....
accept:?Resource?temporarily?unavailable
可以看到,當(dāng)accept()的資源不可用(沒有任何未處理的等待連接的請求)時,程序就會自動返回。
2.select()
使用fcntl()函數(shù)雖然可以實(shí)現(xiàn)非阻塞I/O或信號驅(qū)動I/O,但在實(shí)際使用時往往會對資源是否準(zhǔn)備完畢進(jìn)行循環(huán)測試,這樣就大大增加了不必要的CPU資源的占用。在這里可以使用select()函數(shù)來解決這個問題,同時,使用select()函數(shù)還可以設(shè)置等待的時間,可以說功能更加強(qiáng)大。下面是使用select()函數(shù)的服務(wù)器端源代碼??蛻舳顺绦蚧旧吓c10.2.3小節(jié)中的例子相同,僅加入一行sleep()函數(shù),使得客戶端進(jìn)程等待幾秒鐘才結(jié)束。
/*?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;/*?允許重復(fù)使用本地地址與套接字進(jìn)行綁定?*/
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");
/*將調(diào)用socket()函數(shù)的描述符作為文件描述符*/
FD_ZERO(&inset);
FD_SET(sockfd,?&inset);
while(1)
{
tmp_inset?=?inset;
sin_size=sizeof(struct?sockaddr_in);
memset(buf,?0,?sizeof(buf));
/*調(diào)用select()函數(shù)*/
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)
{?/*?服務(wù)端接收客戶端的連接請求?*/
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?/*?處理從客戶端發(fā)來的消息?*/
{
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);
}
運(yùn)行該程序時,可以先啟動服務(wù)器端,再反復(fù)運(yùn)行客戶端程序(這里啟動兩個客戶端進(jìn)程)即可,服務(wù)器端運(yùn)行結(jié)果如下所示:
$?./server
listening....
New?connection?from?4(socket)?????????????????/*?接受第一個客戶端的連接請求*/
Received?a?message?from?4:?Hello,First!????/*?接收第一個客戶端發(fā)送的數(shù)據(jù)*/
New?connection?from?5(socket)??????????????/*?接受第二個客戶端的連接請求*/
Received?a?message?from?5:?Hello,Second!???/*?接收第二個客戶端發(fā)送的數(shù)據(jù)*/
Client?4(socket)?has?left???????????????????/*?檢測到第一個客戶端離線了*/
Client?5(socket)?has?left???????????????????/*?檢測到第二個客戶端離線了*/
$?./client?localhost?Hello,First!?&?./client?localhost?Hello,Second
總結(jié)
以上是生活随笔為你收集整理的linux如何实现网络高级编程,嵌入式Linux网络编程之:网络高级编程-嵌入式系统-与非网...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 老版本mac如何升级11mac电脑如何更
- 下一篇: 9050 端口 linux 进程,win