`
helloyesyes
  • 浏览: 1304066 次
  • 性别: Icon_minigender_2
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

Linux Socket学习(七)

阅读更多
将地址绑定到一个套接口

在前面的章节中我们准备了足够的知识来创建套接,并且格式化套接口地址。这一章将会这些基础上进行扩展我们将会理解bind是如何工作的,并且如何来正确的使用。

在这一章,我们将会学到下列内容:
bind函数如何将一个地址赋给一个套接口
如何由一个已经具有地址的套接口得到本地套接口地址
如何得到同等的套接口地址
bind如何选择用于通信的网络接口

bind函数的目的

当我们用socket函数创建套接口时,他们是无名套接口。当演示socket函数时,这些套接口没有地址,但是也可以使用。然而,这些套接口可以工作只是因为他们是用这样的方法来创建的,在同一个Linux内核内。对于连接两个不同的主机的套接口而言,这是不可以的。

一 个无名套接口是难于使用的。没有人可以向我们的无名套接口发送信息,因为这就像是一个没有电话号码的电话。因而,程序必须将一个名字绑定到套接口,从而可 以通过其他的方法来访问。这就像将一个电话号码指定给某一个新电话,从而可以进行拨打。bind函数允许我们用同样的方式将一个地址赋给一个套接口。

在这一章中名字的内容与主机名没有任何关系。当讨论bind函数时,我们会经常用到名字这个单词,而这是指一个套接口地址。毕竟地址是一个名字的排列。为了避免混淆,在这一章我们会使用地址这个词。

使用bind函数

bind函数的目的是将一个套接口地址赋给一个无名套接口。这个函数的概要如下:

#include <sys/types.h>
include <sys/socket.h>
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);

这个函数接受下列的三个输入参数:
1 由socket函数调用返回的sockfd文件描述符。
2 要赋给套接口的my_addr地址。
3 以字节表示的my_addr的地址长度(参数addrlen)。

如果成功,这个函数会返回0。如果失败则会返回-1,并且将错误号存放在errno变量中。

地 址参数必须为一个指向地址结构的指针。我们将会注意到通常所用的地址类型为sockaddr结构类型。这就意味着我们必须使用C不应该的转换操作符来转换 我们所传递的指针类型,从而来满足编译器的要求。下面的例子演示了一个建立网络地址的bind函数。在这里我们注意inet_aton以及bind函数的 使用。
/*
* af_inet.c
*
* Demonstrating the bind function
* by establishing a Specific AF_INET
* Socket address
*/

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/*
* this function reports the error and
* exits back to the shell
*/
static void bail(const char *on_what)
{
perror(on_what);
}

int main(int argc,char **argv,char **envp)
{
int z; /* Status return code */
int sck_inet; /* Socket */
struct sockaddr_in adr_inet; /*AF_INET*/
int len_inet; /* length */

/* create and IPv4 Inter socket */
sck_inet = socket(AF_INET,SOCK_STREAM,0);

if(sck_inet == -1)
{
bail("socket()");
}

/* create an AF_INET address */
memset(&adr_inet,0,sizeof adr_inet);

adr_inet.sin_family = AF_INET;
adr_inet.sin_port = htons(9000);

inet_aton("127.0.0.24",&adr_inet.sin_addr);

len_inet = sizeof adr_inet;

/* now bind the address to the socket */
z = bind(sck_inet,(struct sockaddr *)&adr_inet,len_inet);

if(z==-1)
{
bail("bind()");
}
/* display all of our bound sockets */
system("netstat -pa --tcp 2>/dev/null |"
"sed -n '1,/^Proto/p;/bind/p'");
close(sck_inet);
return 0;
}
这个程序的输出结果如下所示:
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.24:9000 *:* CLOSE 934/bind

获得套接口地址
如果我们编写的C库函数接收一个套接口作为输入参数,这时我们并不知道这个套接口的地址是多少。这时我们的函数并没有创建这个套接口,除非这个套接口是作为输入传递给我们的函数的,否则我们并不会知道这个地址。函数getsockname(2)函数允许我们获得这个地址。

getsockname函数概要如下:
int getsockname(int s, struct sockaddr *name, socklen_t *namelen)

这个函数接收下列的输入参数:

1 套接口s查询套接口地址
2 指向接收缓冲区的指针(参数name)
3 指向最大长度变量的指针。这个变量以字节方式提供了可以为缓冲区所接受的最大长度。这个值是由实际写入接收缓冲区的字节数来进行更新的。

注意,也bind函数相类似,getsockname使用通用地址结构sockaddr,这是因为他可以用于多种套接口类型。这就意味着我们可能需要在参数中提供的指针上执行C语言转换操作。

长度参数namelen指定了可以在参数中接收的最大字节长度。然而,在返回给调用者之前,namelen的值会被重写来指明有多少字节实际写入输入缓冲区。这会小于或是等于所提供的原始值。

如果函数调用成功则会返回0值。如果发生错误,则会返回-1,错误原因将会存放在变量errno中。

编写一个sock_addr()函数

为了演示getsockname的用法,下面提供一个小函数,这个函数接收一个套接口描述符作为输入。这个函数通过调用getsockname,然后向调用者提者返回一个格式化的字符串,从而可以用在printf调用中。

/*
* sckname.c
*
* Demonstrate getsockname(2):
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/*
* this saves lines of code later:
*/
static void bail(const char *on_what)
{
perror(on_what); /* report error */
exit(1); /* exit programming */
}

/*
* this function accepts as input a socket
* for which a socket address must be
* is converted into a string and returned
*
* if an error occurs,NULL is returned.
*/
char *sock_addr(int s,char *buf,size_t bufsize)
{
int z; /* status return code */
struct sockaddr_in adr_inet; /* AF_INET */
int len_inet; /* length */

/*
* obtain the address of the socket:
*/
len_inet = sizeof adr_inet;

z = getsockname(s,(struct sockaddr *)&adr_inet,&len_inet);

if(z==-1)
return NULL; /* failed */

/*
* convert address into a string
* form that can be displayer:
*/
snprintf(buf,bufsize,"%s:%u",
inet_ntoa(adr_inet.sin_addr),
(unsigned)ntohs(adr_inet.sin_port));
return buf;
}

/*
* main program
*/
int main(int argc,char **argv,char **envp)
{
int z; /* status return code */
int sck_inet; /* socket */
struct sockaddr_in adr_inet; /* AF_INET */
int len_inet; /* length */
char buf[64]; /* work buffer */

/*
* create an IPv4 internet socket:
*/
sck_inet = socket(AF_INET,SOCK_STREAM,0);

if(sck_inet == -1)
bail("socket()");

/*
* create an AF_INET address:
*/
memset(&adr_inet,0,sizeof adr_inet);
adr_inet.sin_family = AF_INET;
adr_inet.sin_port = htons(9000);
inet_aton("127.0.0.24",&adr_inet.sin_addr);
len_inet = sizeof adr_inet;

/*
* now bind the address to the socket:
*/
z = bind(sck_inet,(struct sockaddr *)&adr_inet,len_inet);

if(z==-1)
bail("bind()");

/*
* now test our sock_addr() function:
*/
if(!sock_addr(sck_inet,buf,sizeof buf))
bail("sock_addr()");
printf("Address is '%s'\n",buf);
close(sck_inet);
return 0;
}

这个函数的执行结果如下:
$ ./sckname
Address is '127.0.0.24:9000'
$

获得点套接口地址
在 最后的部分,我们将会看到函数getsockname在获得一个套接口地址是相当有用的。然而,当我们的代码希望确定我们的套接口连接到哪一个远程套接口 地址时需要花费相当的时间。确定一个套接口的远程地址就像当我们接到一个电话时我们要查找出拨打电话人的电话号码一样。

来完成这个任务是getpeername(2)函数。当我们开始检测和编写一个服务器代码时这个函数是相当有用的。在这里进行介绍是因为他与getsockname相类似。getpeername函数概要如下:
#include <sys/socket.h>
int getpeername(int s, struct sockaddr *name, socklen_t *namelen);

在这里我们可看到这个函数的参数与getsockname函数完全相同。

下面的代码定义了一个名为peer_addr()的函数。这个代码的设计与前面的sock_addr()函数相类似,但是这并不是一个完整的代码,因为这里只是显示了函数本身的代码,而没有主程序。

/*
* getpeer.c
*
* Demonstrate getpeername(2):
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/*
* this function accepts as input a socket
* for which a peer socket address must be
* is converted into a string and returned
*
* if and error occurs,NULL is returned
*/
char *peer_addr(int s,char *buf,size_t bufsize)
{
int z; /* status return code */
struct sockaddr_in adr_inet; /* AF_INET */
int len_inet; /* length */

/*
* obtain the address of the socket:
*/
len_inet = sizeof adr_inet;

z = getpeername(s,(struct sockaddr *)&adr_inet,&len_inet);

if(z==-1)
bail("getpeername()");

/*
* convert address into a string
* form that can be displayed:
*/
z = snprintf(buf,bufsize,"%s:%u",
inet_ntoa(adr_inet.sin_addr),
(unsigned)ntohs(adr_inet.sin_port));

if(z==-1)
return NULL;

return buf;
}

接口与地址

在我们继续套接口编程的其他方面之前,有一个我们必须理解的与套接口地址相关的其他概念。这就是接口地址的概念。

使用我们所熟悉的电话作为例子,想像一个总统办公室,在他的桌子上放有两部电话。使用其中的一个他可以与他的妻子进行联系。另一方面,使用红色的电话,他可以与俄罗斯总统进行联系。在某种意义上说,这两部的电话的每一个,是两个不同网络的接口。他们是:
普通的国内电话网
通过安全线的私有网络

在这个例子中的关键点就在于我们必须使用正确的接口来访问正确的网络。例如,总统不可以使用红色的电话与他的妻子进行联系。同样的,国内电话网也不可以拨通俄罗斯总统的电话。

相类似的方式,当我们的套接口程序要指明当试图与远程套接口建立连接所用的接口时需要花费相当的时间。当我们知道只有一个接口可以访问上的网络时就会变得简单了。

绑定一个指定的接口地址

为了给我们的通信指定一个接口,我们需要执行下面的步骤:
1 使用socket创建我们的套接口
2 使用bind函数将我们希望接受连接的接口IP地址绑定到本地套接口

下面的例子演示了如何指定一个网络接口地址。这些工作必须在套接口通信开始之前完成。
nt z;
int sck_inet; /* Socket */
struct sockaddr_in adr_inet; /* AF_INET */
int len_inet; /* length */
sck_inet = socket(AF_INET,SOCK_STREAM,0);
if ( sck_inet == -1 )
abort(); /* Failed */
/* Establish address */
memset(&adr_inet,0,sizeof adr_inet);
adr_inet.sin_family = AF_INET;
adr_inet.sin_port = htons(9000);
adr_inet.sin_addr.s_addr("192.168.0.1");
adr_inet.sin_addr.s_addr == INADDR_NONE )
abort(); /* Failed */
len_inet = sizeof adr_inet;
z = bind(sck_inet, (struct sockaddr *)&adr_inet, len_inet);

绑定任何接口

我们如何接受任何接口的连接呢?我们可以执行下面的步骤:
1 使用socket创建一个套接口
2 使用bind函数将IP地址INADDR_ANY绑定到套接口

如下面的代码所示:
int z;
int sck_inet; /* Socket */
struct sockaddr_in adr_inet; /* AF_INET */
int len_inet; /* length */
sck_inet = socket(AF_INET,SOCK_STREAM,0);
if ( sck_inet == -1 )
abort(); /* Failed */
/* Establish address */
memset(&adr_inet,0,sizeof adr_inet);
adr_inet.sin_family = AF_INET;
adr_inet.sin_port = htons(9000);
adr_inet.sin_addr.s_addr = htonl(INADDR_ANY);
if ( adr_inet.sin_addr.s_addr == INADDR_NONE )
abort(); /* Failed */
len_inet = sizeof adr_inet;
z = bind(sck_inet, (struct sockaddr *)&adr_inet, len_inet);
分享到:
评论

相关推荐

    Linux Socket教程.zip

    Linux Socket学习(十六).txt和Linux Socket学习(十七).txt可能涉及到了更高级的主题,如多路复用I/O,如select()、poll()或epoll(),这些工具可以帮助程序同时处理多个Socket连接。 Linux Socket学习(十四)....

    实战Linux socket编程Linux Socket Programming By Example

    《实战Linux Socket编程》是...总之,《实战Linux Socket编程》的配套源代码是一个宝贵的资源,它使学习者能够动手实践,从而更好地掌握网络编程的核心概念和技术,对于提升Linux系统下的网络编程能力具有重要意义。

    LinuxSocket示例代码

    在IT行业中,Linux Socket是进行网络通信的重要工具,尤其对于系统和网络程序员来说,理解和掌握Linux Socket编程至关重要。本示例代码提供了客户端(client)和服务器端(server)的实现,帮助初学者深入理解如何在...

    实战Linux Socket编程

    在IT领域,Linux Socket编程是网络通信的核心技术之一,它为开发者提供了在Linux操作系统上实现进程间通信(IPC)和网络通信的接口。本实战指南将深入探讨这一主题,帮助你掌握如何在Linux环境中构建高效的网络应用...

    socket_test.zip_Linux下的socket_linux socket_linux socket server_l

    在Linux操作系统中,Socket是一种进程间通信机制,它允许不同进程或者不同计算机之间的通信。本教程将深入探讨Linux下的socket编程,包括服务器和客户端的实现。我们主要关注以下几个知识点: 1. **Socket基本概念*...

    linuxsocket.zip

    本压缩包“linuxsocket.zip”包含了基于TCP/IP协议的socket通信测试代码,是学习Linux应用编程的一个实用资源。这里我们将深入探讨Linux TCP/IP socket编程的相关知识点。 1. **TCP/IP协议栈**:TCP/IP协议栈是...

    linux socket学习.pdf

    本篇文章将根据给定文件“linux socket学习.pdf”的内容进行展开,重点讨论 socket 的定义、如何创建 socket 以及 socket 与其他常见 I/O 操作的区别。 #### 二、理解 Socket ##### 2.1 定义 Socket Socket 可以...

    《实战 Linux Socket编程》练习代码

    通过本书的学习,读者可以掌握如何在Linux环境中使用Socket进行网络通信,构建高性能、稳定的网络应用。下面将根据提供的压缩包文件名“实战 Linux Socket编程代码”来解析其中可能包含的知识点。 1. **Socket基础...

    实战Linux Socket编程.rar

    Linux Socket编程是网络编程的重要组成部分,它为开发者提供...通过这个实战教程,开发者将学习如何在Linux环境中创建和管理Socket,实现网络通信功能,这对于开发服务器应用、网络工具或分布式系统是至关重要的技能。

    linux socket网络驱动深度分析

    在Linux操作系统中,Socket接口是应用程序与网络协议交互的主要接口,它允许程序通过网络发送和接收数据。在本文中,我们将深入探讨“Linux Socket网络驱动深度分析”这一主题,特别是当应用尝试创建一个用于捕获...

    Linux Socket

    Linux Socket是Linux操作系统中用于进程间通信(IPC)的一种接口,它允许程序通过网络协议进行数据传输。在本文中,我们将深入探讨Linux ...通过IBM技术论坛的文章,你可以更深入地了解和学习Linux Socket的各种细节。

    Linux Socket Programming (Linux 套接字编程)

    ### Linux Socket Programming (Linux 套接字编程) #### 知识点概览: 1. **Socket编程基础** ...通过以上知识点的学习,读者可以深入了解Linux环境下的Socket编程,并能够掌握如何设计和实现网络通信程序。

    linux socket 实战编程pdf及源码

    Linux Socket实战编程是深入理解网络通信机制的...总的来说,这份资源对于想要深入理解和精通Linux Socket编程的IT从业者来说是一份宝贵的资料,通过学习和实践,可以显著提升网络编程能力,为职业发展打下坚实基础。

    linux socket programming

    Gay撰写,为读者提供了丰富的实例和深入的理论知识,是学习Linux Socket编程的绝佳资源。 **二、基本Socket概念** ### 1. Socket简介 在Linux环境下,Socket是一种进程间通信(IPC)的方式,它提供了一种在两个...

    Linux Socket两则示例

    在IT行业中,网络通信是至关重要的部分,而Linux Socket编程是实现这一目标的关键技术。Socket是一种接口,允许应用程序通过网络发送和接收数据。本篇将深入探讨标题为"Linux Socket两则示例"的资源,其中包括`echo_...

    linux下的socket聊天室程序

    10. **学习资源**:学习Socket编程,可以参考《UNIX Network Programming》等经典书籍,同时网上有许多关于Linux Socket编程的教程和示例代码可供学习。 总之,"Linux下的socket聊天室程序"是一个很好的实践项目,...

    实战Linux Socket 编程.rar

    本资源“实战Linux Socket编程”旨在帮助你深入理解并掌握这一关键技能,尤其对于那些希望在嵌入式领域有所建树的开发者来说,它是不可或缺的学习资料。 在Linux系统中,Socket编程主要涉及以下几大知识点: 1. **...

    Linux Socket Programming By Example

    《Linux Socket编程示例》...以上仅为《Linux Socket编程示例》部分章节的知识点总结,实际书中还包含了更多深入的技术细节和实战案例,对于希望掌握Linux环境下网络编程技术的学习者而言,是一本不可多得的参考书籍。

    实战Linux Socket编程源码

    Linux Socket编程是网络编程的重要组成部分,它允许...总之,"实战Linux Socket编程源码"提供了一个实践Socket编程和多客户端处理的平台,通过对源代码的学习和分析,可以加深对Socket编程的理解,提升网络编程技能。

Global site tag (gtag.js) - Google Analytics