您的位置:首页 > 运维架构 > Linux

Linux C 第十九章 Socket 相关函数

2018-01-20 18:23 323 查看

第十九章 Socket 相关函数

相关头文件:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

accept : int accept(int s, struct sockaddr* addr, int *addrlen);
接受socket连线
accept()用来接受参数s的socket连线。参数s的socket必需先经bind(),listen()函数处理过,当有连线进来时
accept()会返回一个新的socket处理代码,往后的数据传送与读取就是经由新的socket处理,而原来参数s的
socket参继续使用accept()来接受新的连线要求。连线成功时,参数addr所指的结构会被系统填入远程主机的
地址数据,参数addrlen为sockaddr的结构长度。
成功返回新的socket处理代码,失败返回-1,错误代码存于errno中。
EBADF       参数s非合法socket处理代码
EFAULT      参数addr指针指向无法存取的内存空间
ENOTSOCK    参数s为一文件描述符,非socket
EOPNOTSUPP  指定的socket并非SOCK_STREAM
EPERM       防火墙(firewall)拒绝此连线
ENOBUFS     系统缓冲内存不足
ENOMEM      核心内存不足

bind  :int bind(int sockfd, struct sockaddr* my_addr, int addrlen);
对socket定位
bind()用来设置给参数sockfd的socket一个名称。此名称由参数my_addr指向一sockaddr结构,对于不同的socket domain
定义了一个通用的数据结构:
struct sockaddr
{
unsigned short int sa_family;
char sa_data[14];
};
sa_family   为调用socket()时的domain参数,即AF_xxxx值。
sa_data     最多使用14个字符长度。
此sockaddr结构会因使用不同的socket domain而有不同结构定义,
如使用AF_INET domain其sockaddr结构定义为:
struct socketaddr_in
{
unsigned short int sin_family;
uint16_t sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8];
};
struct in_addr
{
uint32_t s_addr;
};
sin_family      即为family
sin_port        为使用的port编号
sin_addr.s_addr 为IP地址
sin_zero        未使用
参数addrlen为sockaddr的结构长度。
成功则返回0,失败则返回-1,错误代码存于errno中。
EBADF       参数sockfd非合法socket处理代码
EACCESS     权限不足
ENOTSOCK    参数sockfd为一文件描述符,非socket

connect :int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
建立socket连线
connect()用来将参数sockfd的socket连至serv_addr指定的网络地址。结构sockaddr请参数bind().
参数addrlen为sockaddr的结构长度。
成功则返回0,失败则返回-1,错误代码存于errno中。
EBADF       参数sockfd非合法socket处理代码
EFAULT      参数serv_addr指针指向无法存取的存内空间
ENOTSOCK    参数sockfd为一文件描述符,非socket
EISCONN     参数sockfd的socket已是连接状态
ECONNERFUSED    连线要求被server拒绝
ENETUNREACH     无法传送数据包至指定的主机
EAFNOSUPPORT    sockaddr结构的sa_family不正确
EALERADY        socket为不可阻断且先前的连线操作还未完成
/*利用socket 的TCP client 连线TCP server,并将键盘输入的字符串传送给server.
* TCP server范例请参考listen()
*/
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT    1234 /*使用的port端口号*/
#define SERVER_IP "127.0.0.1" /*Server IP*/
main()
{
int s;
struct sockaddr_in addr;
char buffer[256];
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0){
perror("socket:");
exit(1);
}

/*填写sockaddr_in 结构*/
bzero(*addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = inet_addr(SERVER_IP);

/*尝试连接*/
if(connect(s, &addr, sizeof(addr)) < 0){
perror("connect:");
exit(1);
}

/*接收由server端传来的消息*/
recv(s, buffer, sizeof(buffer), 0);
printf("%s\n", buffer);
while(1){
bzero(buffer, sizeof(buffer));
/* 从标准输入设备读取字符串*/
read(STDIN_FILENO, buffer, sizeof(buffer));
/*将字符串传给server端*/
if (send(s, buffer, sizeof(buffer), 0) < 0){
perror("send:");
exit(1);
}
}
}

endprotoent : void endprotoent(void);
结束网络协议数据的读取。
endprotoent()用来关闭由 getprotoent()所打开的文件。

endservent :void endservent(void);
结束网络服务数据的读取,
endservent()用来关闭由 getservent()所打开的文件。

gethostbyaddr :struct hostent * gethostbyaddr(const char* addr, int len, int type);
由IP地址取得网络数据,
gethostbyaddr()会返回一个hostent结构, addr可以为IPv4 或IPv6的 IP地址, len addr的长度, type 可以为AF_INET;
成功返回hostent结构指针,若有错误则返回NULL指针。错误原因则存于h_errno变量
HOST_NOT_FOUND      指不到指定的主机
NO_ADDRESS          该主机有名称却无IP地址
NO_RECOVERY         域名服务器有错误发生
TRY_AGAIN           请再调用一次
#include <netdb.h>
#include <sys/sockaddr>
main(int argc, char *argv[])
{
struct hostent *host;
if(argc < 2) return;
host = gethostbyaddr(argv[1], sizeof(argv[1]), AF_INET);
if(host == (struct hostent *)NULL)
herror("gethostbyaddr:");
else
{
printf("name :%s\n", host->h_name);
printf("type :%d\n", host->h_addrtype);
printf("addr :%s\n", host->h_addr_list[0]);
}
}

gethostbyname :struct hostent *gethostbyname(const char *name);
gethostbyname()会返回一个hostent结构,参数name可以为一个主机名称或IPv4/IPv6的IP地址。
结构hostent定义如下:
struct hostent{
char *h_name;       //正式的主机名称
char **h_aliases;   //指向主机名称的其他别名
int h_addrtype;     //地址的型态,通常是AF_INET
int h_length;       //地址的长度
char **h_addr_list; //从域名服务器取得该主机的所有地址
};
成功返回hostent结构指针,若有错误则返回NULL指针。错误原因则存于h_errno变量
HOST_NOT_FOUND      找不到指定的主机
NO_ADDRESS          该主机有名称却无IP地址
NO_RECOVERY         域名服务器有错误发生
TRY_AGAIN           请再调用一次
/*利用gethostbyname()的简单反查IP程序*/
#include <stdio.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
main(int argc, char **argv)
{
struct hostent *hp;
struct in_addr in;
struct sockaddr_in local_addr;
if(argc < 2) return;
if (!(hp = gethostbyname(argv[1]))){
fprintf(stderr, "Can't resolve host.\n");
exit(1);
}
memcpy(&local_addr.sin_addr.sa_addr, hp->h_addr, 4);
in.s_addr = local_addr.sin_addr.s_addr;
printf("Domain Name :%s\n", argv[1]);
printf("IP Address :%s\n", inet_ntoa(in));
}

getprotobyname :struct protoent *getprotobyname(const char *name);
由网络协议名称取得协议数据
getprotobyname()会返回一个protoent结构,参数name为欲查询的网络协议名称。此函数会从/etc/protocols中
查找符合条件的数据并由结构protoent返回。
成功则返回protoent结构指针,若有错误或找不到符合的数据则返回NULL指针。
/* 取得icmp协议数据 */
#include <netdb.h>
main()
{
struct protoent *protocol;
protocol = getprotobyname("icmp");
printf("protocol name :%s\n", protocol->p_name);
printf("protocol number :%d\n", protocol->p_proto);
printf("protocol alias :%s\n", protocol->p_aliases[0]);
}

getprotobynumber :struct protoent *getprotobynumber(int proto);
由网络协议编号取得协议数据
getprotobynumber()会返回一个protoent结构,参数proto为欲查询的网络协议编号。此函数会从/etc/protocols中
查找符合条件的数据并由结构protoent返回。
成功则返回protoent结构指针,若有错误或找不到符合的数据则返回NULL指针。
/* 取得协议编号0~4的协议数据 */
#include <netdb.h>
main()
{
int number;
struct protoent *protocol;
for(number=0; i<=4; i++)
{
protocol = getprotobynumber(number);
if (protocol == (struct protoent *)NULL) continue;
printf("%2d :%-10s: %-10s\n", protocol->p_proto, protocol->p_name, protocol->p_aliases[0]);
}
}

getprotoent :struct protoent *getprotoent(void);
取得网络协议数据
getprotoent()会打开/etc/protocols,然后读取一行数据后由结构protoent返回。之后再调用此函数则会断续读取
下一项数据,除非已到文件尾时返回NULL指针。
结构protoent定义如下:
struct protoent{
char *p_name;   /* official protocol name */
char *p_aliases;    /* alias list */
int p_proto;    /* protocol number */
};
成功则返回protoent结构指针,若有错误或找不到符合的数据则返回NULL指针。
/* 取得所有协议数据 */
#include <netdb.h>
main()
{
struct protoent *p;
while(p = getprotoent())
{
printf("%s  %s %d\n", p->p_name, p->p_aliases, p->p_proto);
}
endprotoent();
}

getservbyname :struct servent *getservbyname(const char *name, const char *proto);
依名称取得网络服务的数据
getservbyname()会返回一个servent结构,参数name可以为一个网络服务名称,参数proto则为该服务所使用的协议。
此函数会从/etc/services中查找符合条件的数据并由结构servent返回。
成功返回servent结构指针,若有错误则返回NULL
#include <netdb.h>
main()
{
struct servent *s;
s = getservbyname("telnet", "tcp");
printf("%s  %d/%s\n", s->s_name, ntohs(s->s_port), s->s_proto);
}

getservbyport :struct servent *getservbyport(int port, const char *proto);
依端口号取得网络服务的数据
getservbyport()会返回一个servent结构,参数port可以为一个端口号,参数proto则为该服务所使用的协议。
此函数会从/etc/services中查找符合条件的数据并由结构servent返回。
参数port必须先由htons()转换
成功则返回servent结构指针,若有错误则返回NULL指针。
#include <netdb.h>
main()
{
struct servent *s;
s = getservbyport(htons(23), "tcp");
printf("%s %d/%s\n", s->s_name, ntohs(s->s_port), s->s_proto);
}

getservent :struct servent *getservent(void);
取得主机网络服务的数据
getservent()会打开/etc/services,然后读取一行数据后由结构servent返回。之后再调用此函数则会继续读取下
一项数据,除非已到文件结尾时返回NULL指针。
结构servent定义如下:
struct servent
{
char    *s_name;    //正式的服务名称;
char    **s_aliases; //别名列表
int     s_port;     //所使用的端口号;
char    *s_proto;   //所使用的协议名称;
};
成功则返回servent结构指针,若有错误则返回NULL指针。
#include <netdb.h>
main()
{
struct servent *s;
while((s = getservent()) != NULL)
{
printf("%s   %d/%s\n", s->s_name, ntohs(s->s_port), s->s_proto);
}
}

getsockopt :int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen);
取得socket状态
getsockopt()会将参数s所指定的socket状态返回。参数optname代表欲取得何种选项状态,而参数optval则指向欲保存
结果的内存地址,参数optlen则为该空间的大小。
成功返回0,若有错误返回-1,错误原因存于errno中。
EBADF       参数s并非合法的socket处理代码
ENOTSOCK    参数s为一文件描述符,非socket
ENOPROTOOPT 参数optname指定的项选不正确
EFAULT      参数optval指针指向无法存取的内存空间
#include <sys/types.h>
#include <sys/socket.h>
main()
{
int s, optval, optlen = sizeof(int);
if ( (s=socket(AF_INET, SOCK_STREAM, 0)) < 0)
perror("socket:");
getsockopt(s, SOL_SOCKET, SO_TYPE, *optval, &optlen);
printf("optval = %d\n", optval);
close(s);
}

herror :void herror(const char *s);
打印出网络错误原因信息字符串
herror()用来将上一个网络函数发生错误的原因输出到标准错误(stderr)。参数s所指的字符会先打印出来。后面再加上
错误的原因字符串。此错误原因系依照全局变量h_errno的值来决定要输出的字符串。

hstrerror :const char *hstrerror(int err);
返回网络错误原因的描术字符
hstrerror()用来依参数err的错误代码来查询socket错误原因的描述字符串,然后将该字符串指针返回。
返回描述错误原因的字符串指针。
/* 显示错误代码0~5的错误原因 */
#include <netdb.h>
main()
{
int i;
for (i=0; i<6; i++)
{
printf("%d :%s\n", i, hstrerror(i));
}
}

htonl :unsigned long int htonl(unsigned long int hostlong);
将一个32位数主机字节顺序转换成网络字节顺序
htonl()用来将参数指定的32位hostlong转换成网络字节顺序
返回对应的网络字节顺序

htons :unsigned short int htons(unsigned short int hostshort);
将一个16位主机字节顺序转换成网络字节顺序
htonl()用来将参数指定的16位hostshort转换成网络字节顺序
返回对应的网络字节顺序

inet_addr :unsigned long int inet_addr(const char *cp);
将网络地址转换成网络二进制的数字
inet_addr()用来将参数cp所指的网络地址字符串转换成网络所使用的二进制数字。网络地址字符串是以数字和点组成的字符串,
例如:"192.168.88.68"
成功返回对应的网络二进制的数字,失败返回-1

inet_aton :int inet_aton(const char *cp, struct in_addr *inp);
将网络地址转换成网络二进制的数字
inet_aton()用来将参数cp所指的网络地址字符串转换成网络所使用的二进制数字,然后存于参数inp所指的in_addr结构中
结构in_addr定义如下:
struct in_addr
{
unsigned long int s_addr;
};
网络地址字符串是以数字和点组成的字符串,例如:"192.168.88.68"
成功返回非0值,失败返回0

inet_ntoa :char *inet_ntoa(struct in_addr in);
将网络二进制的数字转换成网络地址
inet_ntoa()用来将参数in所指的网络二进制的数字转换成网络地址,然后将指向此网络地址字符串的指针返回。
结构in_addr定义如下:
struct in_addr
{
unsigned long int s_addr;
};
网络地址字符串是以数字和点组成的字符串,例如:"192.168.88.68"
成功返回非0值,失败返回NULL

listen :int listen(int s, int backlog);
等待连接
listen()用来等待参数s的socket连线。参数backlog指定同时能处理的最大连接要求,如果连接数目达此上限则client端
将收到ECONNERFUSED的错误。listen()并未开始接受连线,只是设置socket为listen模式,真正接受client端连线的是
accept()。通常listen()会在socket(),bind()之后调用,接着才调用accept()。
listen()只适用SOCK_STREAM或SOCK_SEQPACKET的socket类型。如果scocket为AF_INET则参数backlog最大值可设为128.
成功返回0,发生错误返回-1,错误原因存于errno中。
EBADF       参数sockfd非合法socket处理代码
EACCESS     权限不足
EOPNOTSUPP  指定的socket并未支持listen模式
/*利用socket的TCP server,此程序会接收由TCP client传来的字符串并显示 */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define PORT 1234 //使用的端口号
#define MAXSOCKFD   10 //可同时服务的最大连线数目
main()
{
int sockfd, newsockfd, is_connected[MAXSOCKFD], fd;
struct sockaddr_in addr;
int addr_len = sizeof(struct sockaddr_in);
fd_set readfds;
char buffer[256];
char msg[] = "Welcome to server";
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0))<0)
{
perror("socket:");
exit(1);
}
/*填写sockaddr_in结构*/
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sockfd, &addr, sizeof(addr)) < 0)
{
perror("bind:");
exit(1);
}
if(listen(sockfd, 3) < 0)
{
perror("listen:");
exit(1);
}
/*清除连线状态旗标*/
for(fd = 0; fd < MAXSOCKFD; fd++)
{
is_connected[fd] = 0;
while(1)
{
FD_ZERO(&readfds);
FD_SET(sockfd, &readfds);
for(fd = 0; fd < MAXSOCKFD; fd++)
{
if(is_connected[fd])FD_SET(fd, &readfds);
if(!select(MAXSOCKFD, &readfds, NULL, NULL, NULL))continue;
/*判断是否有新连线或新信息进来*/
for(fd=0; fd<MAXSOCKFD; fd++)
{
if(FD_ISSET(fd, &readfds))
{
if(sockfd == fd)
{
/*接收新连线*/
if((newsockfd = accept(sockfd, &addr, &addr_len))<0)
{
perror("accept:");
}

/*将字符串传给client端*/
write(newsockfd, msg, sizeof(msg));
is_connected[newsockfd] = 1;
printf("connect from %s\n", inet_ntoa(addr.sin_addr));
} else {
/*接收新信息*/
bzero(buffer, sizeof(buffer));
if (read(fd, buffer, sizeof(buffer)) <= 0)
{
/*连线中断,清除连线状态旗标*/
printf("Connection closed\n");
is_connected[fd] = 0;
close(fd);
}else{
printf("%s", buffer);
}

}
}
}
}
}
}

}
ntohl :unsigned long int ntohl(unsigned long int netlong);
将32位网络字节顺序转换成主机字节顺序
ntohl()用来将参数指定的32位netlong转换成主机字节顺序。
返回对应的主机字节顺序。

ntohs :unsigned short int ntohs(unsigned short int netshort);
将16位网络字节顺序转换成主机字节顺序
ntohs()用来将参数指定的16位netshort转换成主机字节顺序。
返回对应的主机字节顺序。

recv :int recv(int s, void *buf, int len, unsigned int flags);
经socket接收数据
recv()用来接收远端主机经指定的socket传来的数据,并把数据存到由参数buf指向的内存空间,参数len为
可接收数据的最大长度。
参数flags一般设为0,其它定义值如下:
MSG_OOB         接收以out-of-band送出的数据
MSG_PEEK        返回来的数据并不会在系统内删除,如果再调用recv()会返回相同的数据
MSG_WAITALL     强迫接受到len大小的数据后才能返回,除非有错误或信号产生
MSG_NOSIGNAL    此操作不愿被SIGPIPE信号中断

成功返回接收到的字符数,失败返回-1,错误代码存于errno中。
EBADF       参数s非合法socket处理代码
EFAULT      参数中有一指针指向无法存取的内存空间
ENOTSOCK    参数s为一文件描述符,非socket
EINTR       被信号所中断
EAGAIN      此动作会令进程阻断,但参数s的socket为不可阻断
ENOMEM      系统缓冲内存不足
EINVAL      传给系统调用的参数不正确

recvfrom :int recvfrom(int s, void *buf, int len, unsigned int flags struct sockaddr *from, int *fromlen);
recvfrom()用来接收远程主机经指定的socket传来的数据,并把数据存到由参数buf指向的内存空间,参数len为可接收
数据的最大长度。参数flags一般设为0,参数from用来指定欲传送网络地址。参数fromlen为sockaddr的结构长度。
参数flags一般设为0,其它定义值如下:
MSG_OOB         接收以out-of-band送出的数据
MSG_PEEK        返回来的数据并不会在系统内删除,如果再调用recv()会返回相同的数据
MSG_WAITALL     强迫接受到len大小的数据后才能返回,除非有错误或信号产生
MSG_NOSIGNAL    此操作不愿被SIGPIPE信号中断

成功返回接收到的字符数,失败返回-1,错误代码存于errno中。
EBADF       参数s非合法socket处理代码
EFAULT      参数中有一指针指向无法存取的内存空间
ENOTSOCK    参数s为一文件描述符,非socket
EINTR       被信号所中断
EAGAIN      此动作会令进程阻断,但参数s的socket为不可阻断
ENOBUFS     系统缓冲内存不足
ENOMEM      核心内存不足
EINVAL      传给系统调用的参数不正确
/*利用socket 的UDP client
*此程序会连线UDP server, 并将键盘输入的字符串传送给server
*UDP server请参考sendto()
*/
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 2345
#define SERVER_IP   "127.0.0.1"
main()
{
int s, len;
struct sockaddr_in addr;
int addr_len = sizeof(struct sockaddr_in);
char buffer[256];
/*建立socket*/
if((s = socket(AF_INET, SOCK_DGRAM, 0))< 0) {
perror("socket:");
exit(1);
}
/*填写sockaddr_in结构*/
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = inet_addr(SERVER_IP);
while(1)
{
bzero(buffer, sizeof(buffer));
/*从标准输入设备读取字符串*/
len = read(STDIN_FILENO, buffer, sizeof(buffer));
/*将字符串传送给server端*/
sendto(s, buffer, len, 0, &addr, addr_len);
/*接收server返回的字符串*/
len = recvfrom(s, buffer, sizeof(buffer), 0, &addr, &addr_len);
printf("receive: %s\n", buffer);
}
}

recvmsg :int recvmsg(int s, struct msghdr *msg, unsigned int flags);
经socket接收数据
recvmsg()用来接收远程主机经指定的socket传来的数据。参数s为已建立好连线的socket,如果利用UDP协议则不需经
过连线操作。参数msg指向欲连线的数据结构内容,参数flags一般为0,详细参考send()。msghdr结构定义参考sendmsg()
成功返回接收到的字符数,失败返回-1,错误代码存于errno中。
EBADF       参数s非合法socket处理代码
EFAULT      参数中有一指针指向无法存取的内存空间
ENOTSOCK    参数s为一文件描述符,非socket
EINTR       被信号所中断
EAGAIN      此动作会令进程阻断,但参数s的socket为不可阻断
ENOBUFS     系统缓冲内存不足
ENOMEM      核心内存不足
EINVAL      传给系统调用的参数不正确
范例请参考recvfrom();

send :int send(int s, const void *msg, int len, unsigned int flags);
经socket传送数据
send()用来将数据由指定的socket传给对方主机。参数s为已建立好连线的socket。参数msg指向欲连线的数据内容,参数
len则为数据长度。参数flags一般为0,其它定义值如下:
MSG_OOB         传送的数据以out-of-band送出
MSG_DONTROUTE   取消路由表(routing-table)查询
MSG_DONTWAIT    设置为不可阻断运作
MSG_NOSIGNAL    此动作不愿被SIGPIPE信号中断
成功则返回实际传送出去的字符数,失败返回-1,错误代码存于errno中。
EBADF       参数s非合法socket处理代码
EFAULT      参数中有一指针指向无法存取的内存空间
ENOTSOCK    参数s为一文件描述符,非socket
EINTR       被信号所中断
EAGAIN      此动作会令进程阻断,但参数s的socket为不可阻断
ENOBUFS     系统缓冲内存不足
ENOMEM      核心内存不足
EINVAL      传给系统调用的参数不正确
范例请参考connect();

sendmsg :int sendmsg(int s, const struct msghdr *msg, unsigned int flags);
经socket传送数据
sendmsg()用来将数据由指定的socket传给对方主机。参数s为已建立好连线的socket,如果利用UDP协议则不需要经过
连线操作。参数msg指向欲连线的数据内容,参数flags一般为0。
结构msghdr定义如下:
struct msghdr
{
void *msg_name;     /*Address to send to/receive from.*/
socklen_t msg_namelen; /*Length of address data.*/
struct iovec *msg_iov; /*Vector of data to send/receive into.*/
size_t msg_iovlen;  /*Number of elements in ther vector.*/
void *msg_control;  /*Ancillary data.*/
size_t msg_controllen; /*Ancillary data buffer length.*/
int msg_flags; /*Flags on received message.*/
};
成功则返回实际传送出去的字符数,失败返回-1,错误代码存于errno中。
EBADF       参数s非合法socket处理代码
EFAULT      参数中有一指针指向无法存取的内存空间
ENOTSOCK    参数s为一文件描述符,非socket
EINTR       被信号所中断
EAGAIN      此动作会令进程阻断,但参数s的socket为不可阻断
ENOBUFS     系统缓冲内存不足
ENOMEM      核心内存不足
EINVAL      传给系统调用的参数不正确
范例请参考sendto();

sendto : int sendto(int s, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen);
经socket传送数据
sendto()用来将数据由指定的socket传给对方主机。参数s为已建立好连线的socket, 如果利用UDP协议则不需经过连线操作。
参数msg指向欲连线的数据内容,参数len则为数据长度。参数flags一般为0。参数to用来指定欲传送的网络地址,结构sockaddr
请参考bind()。参数tolen为sockaddr的结构长度。
成功则返回实际传送出去的字符数,失败返回-1,错误代码存于errno中。
EBADF       参数s非合法socket处理代码
EFAULT      参数中有一指针指向无法存取的内存空间
ENOTSOCK    参数s为一文件描述符,非socket
EINTR       被信号所中断
EAGAIN      此动作会令进程阻断,但参数s的socket为不可阻断
ENOBUFS     系统缓冲内存不足
ENOMEM      核心内存不足
EINVAL      传给系统调用的参数不正确
/*利用socket的UDP Server
*此程序会接收由UDP client传来的字符串然后再传送回client.
*TCP client范例参考recvfrom();
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define PORT 2345
main()
{
int sockfd , len;
struct sockaddr_in addr;
int addr_len = sizeof(struct sockaddr_in);
char buffer[256];
/*建立socket*/
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket:");
exit(1);
}
/*填写sockaddr_in结构*/
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sockfd, &addr, sizeof(addr)) <0)
{
perror("error:");
exit(1);
}

while(1)
{
/*接收client端传来的字符串*/
bzero(buffer, sizeof(buffer));
len = recvfrom(sockfd, buffer, sizeof(buffer), 0, &addr, &addr_len);
/*显示client端的网络IP地址*/
printf("receive from %s\n", inet_ntoa(addr.sin_addr));
/*将字符串返回给client端*/
sendto(sockfd, buffer, len, 0, &addr, addr_len);
}
}

setprotoent :void setprotoent(int stayopen);
打开网络协议的数据文件
setprotoent()用来打开/etc/protocols,如果参数stayopen值为1,则接下来的getprotobyname()或getprotobynumber()将
不会自动关闭此文件。

setservent :void setservent(int stayopen);
打开主机网络服务的数据文件
void setservent()用来打开/etc/services,如果参数stayopen值为1,则接下来的getservbyname()或getservbynumber()将
不会自动关闭此文件。

setsockopt :int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
设置socket状态
setsockopt()用来设置参数s所指定的socket状态。参数level代表欲设置的网络层,一般设成SOL_SOCKET以存取socket层。
参数optname代表欲设置的选项,有下列几种数值:
SO_DEBUG            打开或关闭调试模式
SO_REUSEADDR        允许bind()过程中本地地址可重复使用
SO_TYPE             返回socket型态(如:SOCK_STREAM)
SO_ERROR            返回socket已发生的错误原因
SO_DONTROUTE        送出的数据包不要利用路由设备来传输
SO_BROADCAST        使用广播方式传送
SO_SNDBUF           设置送出的缓冲区大小
SO_RCVBUF           设置接收的缓冲区大小
SO_KEEPALIVE        定期确定连线是否已终止
SO_OOBINLINE        当接收到OOB(out-of-band)数据时马上送出至标准输入设备
SO_LINGER           确保数据安全且可靠的传送出去
参数optval代表欲设置的值,参数optlen则为optval的长度;
成功则返回0,失败则返回-1,错误代码存于errno中。
EBADF       参数s非合法socket处理代码
ENOTSOCK    参数s为一文件描述符,非socket
ENOPROTOOPT 参数optname指定的选项不正确
EFAULT      参数optval指针指向无法存取的内存空间
范例请参考getsockopt();

shutdown :int shutdown(int s, int how);
终止socket通信
shutdown()用来终止参数s所指定的socket连线。参数是连线中的socket处理代码,参数how有下列几种情况:
how = 0     终止读取操作
how = 1     终止传送操作
how = 2     终止读取及传送操作
成功则返回0,失败则返回-1,错误代码存于errno中。
EBADF       参数s非合法socket处理代码
ENOTSOCK    参数s为一文件描述符,非socket
ENOTCONN    参数s指定的socket并未连线

socket :int socket(int domain, int type, int protocol);
建立一个socket通信
socket()用来建立一个新的socket,也就是向系统注册,通知系统建立一个通信端口。参数domain指定使用何
种的地址类型,完整定义在/usr/include/bits/socket.h常用协议如下:
PF_UNIX/PF_LOCAL/AF_UNIX/AF_LOCAL       UNIX进程通信
PF_INET/AF_INET                         IPv4网络协议
PF_INET6/AF_INET6                       IPv6网络协议
PF_IPX/AF_IPX                           IPX-Novell协议
PF_NETLINK/AF_NETLINK                   内核用户接口设备
PF_X25/AF_X25                           ITU-T X.25/ISO-8208协议
PF_AX25/AF_AX25                         业余无线AX.25协议
PF_ATMPVC/AF_ATMPVC                     存取原始ATM PVCs
PF_APPLETALK/AF_APPLETALK               Appletalk(DDP)协议
PF_PACKET/AF_PACKET                     初级封包接口

参数type有以下几种取值:
SOCK_STREAM             提供双向连续且可靠的数据流,即TCP。支持OOB(out-of-band)机制。在所有数据
传送前必须使用connect()来建立连线状态
SOCK_DGRAM              使用不连续不可靠的数据包连线
SOCK_SEQPACKET          提供连续可靠的数据包连接
SOCK_RAM                提供原始网络协议存取
SOCK_PACKET             提供和网络驱动程序直接通信

参数protocol用来指定socket所使用的传输协议编号,通常此参数不用管,设为0即可
成功则返回socket处理代码,失败则返回-1
EPROTONOSUPPORT         参数domain指定的类型不支持参数type或protocol指定的协议
ENFILE                  内核内存不足,无法建立新的socket结构
EMFILE                  进程文件表溢出,无法建立新的socket
EACCESS                 权限不足,无法建立参数type或protocol指定的协议
ENOBUFS/ENOMEM          内存不足。
EINVAL                  参数domain/type/protocol不会法
范例请参考connect()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: