linux网络编程--socket(3)

 关于linux的读写操作

 

建立了连接,就可以进行通讯了,往文件描述符里读写,和读写文件是一样的.

 

写函数:

ssize_t write(int fd,(void *)buf,size_t nbytes)

将buf中的nbytes写入到fd中,成功时返回所写的字节数,失败时返回-1,并写入errno变量.

当我们象套接字写数据时,可能会有两种情况:

a.write的返回值大于0,表示写了部分或者是全部的数据

b.返回的值小于0,此时出现了错误.我们要根据错误类型来处理

如果错误为EINTR表示在写的时候出现了中断错误.

如果为EPIPE表示网络连接出现了问题(对方已经关闭了连接).

 

读函数:

ssize_t read(int fd,(void *)buf,size_t nbytes)

从fd中读内容,当读成功时,返回读入的字节数,返回是0,责表示已经读入到文件结束了,小于0表示出现了错误.

 

 

数据报的发送:

int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *from,int *fromlen);

int sendto(int sockfd,const void *msg,int len,unsigned int flags,struct sockaddr *to,int tolen);

 

sockfd,buf,len的意义和read,write一样,分别表示套接字描述符,发送或接收的缓冲区及大小.recvfrom负责从sockfd接收数据,如果from不NULL,那么在from里面存储了信息来源的情况,如果对信息的来源不感兴趣,可以将from和fromlen设置为NULL.sendto负责向to发送信息.此时在to里面存储了收信息方的详细资料.

 

 

高级套接字函数:

int recv(int sockfd,void *buf,int len,int flags)

int send(int sockfd,void *buf,int len,int flags)

前面的三个参数和read()和write()函数一样的,参数flags可以是0或者以下任何一项:

MSG_DONTROUTE:是send()函数使用的标识,告诉IP协议,目的主机在本网络上面,没有必要查找路由表;

MSG_OOB:接受或者发送附带数据;

MSG_PEEK:recv()函数使用的参数,表示只从系统缓冲区中读取数据,而不清除系统缓冲的内容,一般在多个进程读写数据的时候使用;

MSG_WAITALL:是recv()函数使用的参数,表示等到所有的数据到达后才返回.使用这个参数时,recv()函数会一直阻塞.

 

套接字的关闭:

套接字的关闭有两个函数:

shutdown()和close()

int shutdown(int sockfd,int howto)

TCP连接是双向的(是可读写的),当我们使用close时,会把读写通道都关闭,有时侯我们希望只关闭一个方向,这个时候我们可以使用shutdown.针对不同的howto,系统回采取不同的关闭方式.

howto=0这个时候系统会关闭读通道.但是可以继续往接字描述符写.

howto=1关闭写通道,和上面相反,着时候就只可以读了.

howto=2关闭读写通道,和close一样 在多进程程序里面,如果有几个子进程共享一个套接字时,如果我们使用shutdown, 那么所有的子进程都不能够操作了,这个时候我们只能够使用close来关闭子进程的套接字描述符.

 

ioctl函数:

ioctl()函数可以控制所有的文件描述符的情况,这里介绍一下控制套接字的选项:

int ioctl(int fd,int req...)

ioctl的控制选项:

SIOCATMARK:是否到达外带标记;

FIOASYNC:异步输入/输出标识;

FIONREAD:缓冲区的可读字节数.

 

 

循环服务器:UDP服务器

UDP循环服务器的实现很简单:UDP服务器每次从套接字上读取一个客户端的请求,处理, 然后将结果返回给客户机.

socket(...);

bind(...);

while(1)

{

recvfrom(...);

process(...);

sendto(...);

}

因为UDP是非面向连接的,没有一个客户端可以老是占住服务端. 只要处理过程不是死循环, 服务器对于每一个客户机的请求总是能够满足.

 

循环服务器:TCP服务器

TCP循环服务器的实现也不难:TCP服务器接受一个客户端的连接,然后处理,完成了这个客户的所有请求后,断开连接.

socket(...);

bind(...);

listen(...);

while(1)

{

accept(...);

while(1)

{

read(...);

process(...);

write(...);

}

close(...);

}

TCP循环服务器一次只能处理一个客户端的请求.只有在这个客户的所有请求都满足后, 服务器才可以继续后面的请求.这样如果有一个客户端占住服务器不放时,其它的客户机都不能工作了.因此,TCP服务器一般很少用循环服务器模型的.

 

并发服务器:TCP服务器

为了弥补循环TCP服务器的缺陷,人们又想出了并发服务器的模型. 并发服务器的思想是每一个客户机的请求并不由服务器直接处理,而是服务器创建一个 子进程来处理.

socket(...);

bind(...);

listen(...);

while(1)

{

accept(...);

if(fork(..)==0)

{

while(1)

{

read(...);

process(...);

write(...);

}

close(...);

exit(...);

}

close(...);

}

TCP并发服务器可以解决TCP循环服务器客户机独占服务器的情况. 不过也同时带来了一个不小的问题.为了响应客户机的请求,服务器要创建子进程来处理. 而创建子进程是一种非常消耗资源的操作.

 

 

声明:网上资料收集,并非本人所写.

 

你可能感兴趣的:(linux网络编程--socket(3))