Linux网络编程入门.docx

上传人:b****8 文档编号:10957311 上传时间:2023-02-24 格式:DOCX 页数:55 大小:39.67KB
下载 相关 举报
Linux网络编程入门.docx_第1页
第1页 / 共55页
Linux网络编程入门.docx_第2页
第2页 / 共55页
Linux网络编程入门.docx_第3页
第3页 / 共55页
Linux网络编程入门.docx_第4页
第4页 / 共55页
Linux网络编程入门.docx_第5页
第5页 / 共55页
点击查看更多>>
下载资源
资源描述

Linux网络编程入门.docx

《Linux网络编程入门.docx》由会员分享,可在线阅读,更多相关《Linux网络编程入门.docx(55页珍藏版)》请在冰豆网上搜索。

Linux网络编程入门.docx

Linux网络编程入门

Linux网络编程入门(转载)

(一)Linux网络编程--网络知识介绍

Linux网络编程--网络知识介绍

客户端和服务端

网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端.

客户端

在网络程序中,如果一个程序主动和外面的程序通信,那么我们把这个程序称为客户端程序。

比如我们使用ftp程序从另外一

个地方获取文件的时候,是我们的ftp程序主动同外面进行通信(获取文件),所以这个地方我们的ftp程序就是客户端程序。

服务端

和客户端相对应的程序即为服务端程序。

被动的等待外面的程序来和自己通讯的程序称为服务端程序。

比如上面的文件获取中,另外一个地方的程序就是服务端,我们从服务端获取文件过来。

互为客户和服务端

实际生活中有些程序是互为服务和客户端。

在这种情况项目,一个程序既为客户端也是服务端。

常用的命令

由于网络程序是有两个部分组成,所以在调试的时候比较麻烦,为此我们有必要知道一些常用的网络命令

netstat

命令netstat是用来显示网络的连接,路由表和接口统计等网络的信息.netstat有许多的选项.

我们常用的选项是-na用来显示详细的网络状态.至于其它的选项我们可以使用帮助手册获得详细的情况.

telnet

telnet是一个用来登录远程的程序,但是我们完全可以用这个程序来调试我们的服务端程序的.

比如我们的服务器程序在监听8888端口,我们可以用

telnetlocalhost8888

来查看服务端的状况.

pingping程序用来判断网络的状态是否正常,最经常的一个用法是

ping192.168.0.1

表示我们想查看到192.168.0.1的硬件连接是否正常

TCP/UDP介绍

TCP(TransferControlProtocol)传输控制协议是一种面向连接的协议,当我们的网络程序使用这个协议的时候,

网络可以保证我们的客户端和服务端的连接是可靠的,安全的.

UDP(UserDatagramProtocol)用户数据报协议是一种非面向连接的协议,

这种协议并不能保证我们的网络程序的连接是可靠的,所以我们现在编写的程序一般是采用TCP协议的.

(二)Linux网络编程--初等网络函数介绍(TCP)

Linux系统是通过提供套接字(socket)来进行网络编程的.网络程序通过socket和其它几个函数的调用,

会返回一个通讯的文件描述符,我们可以将这个描述符看成普通的文件的描述符来操作,这就是linux的设备无关性的好处.

我们可以通过向描述符读写操作实现网络之间的数据交流.

(一)socket

intsocket(intdomain,inttype,intprotocol)

domain:

说明我们网络程序所在的主机采用的通讯协族(AF_UNIX和AF_INET等).

AF_UNIX只能够用于单一的Unix系统进程间通信,

而AF_INET是针对Internet的,因而可以允许在远程

主机之间通信(当我们mansocket时发现domain可选项是PF_*而不是AF_*,因为glibc是posix的实现所以用PF代替了AF,

不过我们都可以使用的).

type:

我们网络程序所采用的通讯协议(SOCK_STREAM,SOCK_DGRAM等)

SOCK_STREAM表明我们用的是TCP协议,这样会提供按顺序的,可靠,双向,面向连接的比特流.

SOCK_DGRAM表明我们用的是UDP协议,这样只会提供定长的,不可靠,无连接的通信.

protocol:

由于我们指定了type,所以这个地方我们一般只要用0来代替就可以了socket为网络通讯做基本的准备.

成功时返回文件描述符,失败时返回-1,看errno可知道出错的详细情况.

(二)bind

intbind(intsockfd,structsockaddr*my_addr,intaddrlen)

sockfd:

是由socket调用返回的文件描述符.

addrlen:

是sockaddr结构的长度.

my_addr:

是一个指向sockaddr的指针.在中有sockaddr的定义

structsockaddr{

unisgnedshortas_family;

charsa_data[14];

};

不过由于系统的兼容性,我们一般不用这个头文件,而使用另外一个结构(structsockaddr_in)来代替.在中有sockaddr_in的定义

structsockaddr_in{

unsignedshortsin_family;

unsignedshortintsin_port;

structin_addrsin_addr;

unsignedcharsin_zero[8];

}

我们主要使用Internet所以

sin_family一般为AF_INET,

sin_addr设置为INADDR_ANY表示可以和任何的主机通信,

sin_port是我们要监听的端口号.sin_zero[8]是用来填充的.

bind将本地的端口同socket返回的文件描述符捆绑在一起.成功是返回0,失败的情况和socket一样

(三)listen

intlisten(intsockfd,intbacklog)

sockfd:

是bind后的文件描述符.

backlog:

设置请求排队的最大长度.当有多个客户端程序和服务端相连时,使用这个表示可以介绍的排队长度.

listen函数将bind的文件描述符变为监听套接字.返回的情况和bind一样.

(四)accept

intaccept(intsockfd,structsockaddr*addr,int*addrlen)

sockfd:

是listen后的文件描述符.

addr,addrlen是用来给客户端的程序填写的,服务器端只要传递指针就可以了.bind,listen和accept是服务器端用的函数,

accept调用时,服务器端的程序会一直阻塞到有一个客户程序发出了连接.accept成功时返回最后的服务器端的文件描述符,

这个时候服务器端可以向该描述符写信息了.失败时返回-1

(五)connect

intconnect(intsockfd,structsockaddr*serv_addr,intaddrlen)

sockfd:

socket返回的文件描述符.

serv_addr:

储存了服务器端的连接信息.其中sin_add是服务端的地址

addrlen:

serv_addr的长度

connect函数是客户端用来同服务端连接的.成功时返回0,sockfd是同服务端通讯的文件描述符失败时返回-1.

(六)实例

服务器端程序

CODE:

[Copytoclipboard]

--------------------------------------------------------------------------------

/*******服务器程序(server.c)************/

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

intmain(intargc,char*argv[])

{

intsockfd,new_fd;

structsockaddr_inserver_addr;

structsockaddr_inclient_addr;

intsin_size,portnumber;

charhello[]="Hello!

AreYouFine?

\n";

if(argc!

=2)

{

fprintf(stderr,"Usage:

%sportnumber\a\n",argv[0]);

exit

(1);

}

if((portnumber=atoi(argv[1]))<0)

{

fprintf(stderr,"Usage:

%sportnumber\a\n",argv[0]);

exit

(1);

}

/*服务器端开始建立socket描述符*/

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

{

fprintf(stderr,"Socketerror:

%s\n\a",strerror(errno));

exit

(1);

}

/*服务器端填充sockaddr结构*/

bzero(&server_addr,sizeof(structsockaddr_in));

server_addr.sin_family=AF_INET;

server_addr.sin_addr.s_addr=htonl(INADDR_ANY);

server_addr.sin_port=htons(portnumber);

/*捆绑sockfd描述符*/

if(bind(sockfd,(structsockaddr*)(&server_addr),sizeof(structsockaddr))==-1)

{

fprintf(stderr,"Binderror:

%s\n\a",strerror(errno));

exit

(1);

}

/*监听sockfd描述符*/

if(listen(sockfd,5)==-1)

{

fprintf(stderr,"Listenerror:

%s\n\a",strerror(errno));

exit

(1);

}

while

(1)

{

/*服务器阻塞,直到客户程序建立连接*/

sin_size=sizeof(structsockaddr_in);

if((new_fd=accept(sockfd,(structsockaddr*)(&client_addr),&sin_size))==-1)

{

fprintf(stderr,"Accepterror:

%s\n\a",strerror(errno));

exit

(1);

}

fprintf(stderr,"Servergetconnectionfrom%s\n",

inet_ntoa(client_addr.sin_addr));

if(write(new_fd,hello,strlen(hello))==-1)

{

fprintf(stderr,"WriteError:

%s\n",strerror(errno));

exit

(1);

}

/*这个通讯已经结束*/

close(new_fd);

/*循环下一个*/

}

close(sockfd);

exit(0);

}

客户端程序

CODE:

[Copytoclipboard]

--------------------------------------------------------------------------------

/*******客户端程序client.c************/

/*******客户端程序client.c************/

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

intmain(intargc,char*argv[])

{

intsockfd;

charbuffer[1024];

structsockaddr_inserver_addr;

structhostent*host;

intportnumber,nbytes;

if(argc!

=3)

{

fprintf(stderr,"Usage:

%shostnameportnumber\a\n",argv[0]);

exit

(1);

}

if((host=gethostbyname(argv[1]))==NULL)

{

fprintf(stderr,"Gethostnameerror\n");

exit

(1);

}

if((portnumber=atoi(argv[2]))<0)

{

fprintf(stderr,"Usage:

%shostnameportnumber\a\n",argv[0]);

exit

(1);

}

/*客户程序开始建立sockfd描述符*/

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

{

fprintf(stderr,"SocketError:

%s\a\n",strerror(errno));

exit

(1);

}

/*客户程序填充服务端的资料*/

bzero(&server_addr,sizeof(server_addr));

server_addr.sin_family=AF_INET;

server_addr.sin_port=htons(portnumber);

server_addr.sin_addr=*((structin_addr*)host->h_addr);

/*客户程序发起连接请求*/

if(connect(sockfd,(structsockaddr*)(&server_addr),sizeof(structsockaddr))==-1)

{

fprintf(stderr,"ConnectError:

%s\a\n",strerror(errno));

exit

(1);

}

/*连接成功了*/

if((nbytes=read(sockfd,buffer,1024))==-1)

{

fprintf(stderr,"ReadError:

%s\n",strerror(errno));

exit

(1);

}

buffer[nbytes]='\0';

printf("Ihavereceived:

%s\n",buffer);

/*结束通讯*/

close(sockfd);

exit(0);

}

MakeFile

这里我们使用GNU的make实用程序来编译.关于make的详细说明见Make使用介绍

CODE:

[Copytoclipboard]

#########Makefile###########

all:

serverclient

server:

server.c

gcc$^-o$@

client:

client.c

gcc$^-o$@

运行make后会产生两个程序server(服务器端)和client(客户端)先运行./serverportnumber&

(portnumber随便取一个大于1204且不在/etc/services中出现的号码就用8888好了),

然后运行./clientlocalhost8888看看有什么结果.(你也可以用telnet和netstat试一试.)

上面是一个最简单的网络程序,不过是不是也有点烦.上面有许多函数我们还没有解释.我会在下一章进行的详细的说明.

(七)总结

总的来说网络程序是由两个部分组成的--客户端和服务器端.它们的建立步骤一般是:

服务器端

socket-->bind-->listen-->accept

客户端

socket-->connect

(三)Linux网络编程--3.服务器和客户机的信息函数

这一章我们来学习转换和网络方面的信息函数.

3.1字节转换函数

在网络上面有着许多类型的机器,这些机器在表示数据的字节顺序是不同的,比如i386芯片是低字节在内存地址的低端,

高字节在高端,而alpha芯片却相反.为了统一起来,在Linux下面,有专门的字节转换函数.

unsignedlonginthtonl(unsignedlonginthostlong)

unsignedshortinthtons(unisgnedshortinthostshort)

unsignedlongintntohl(unsignedlongintnetlong)

unsignedshortintntohs(unsignedshortintnetshort)

在这四个转换函数中,h代表host,n代表network.s代表shortl代表long

第一个函数的意义是将本机器上的long数据转化为网络上的long.其他几个函数的意义也差不多.

3.2IP和域名的转换

在网络上标志一台机器可以用IP或者是用域名.那么我们怎么去进行转换呢?

structhostent*gethostbyname(constchar*hostname)

structhostent*gethostbyaddr(constchar*addr,intlen,inttype)

在中有structhostent的定义

structhostent{

char*h_name;/*主机的正式名称*/

char*h_aliases;/*主机的别名*/

inth_addrtype;/*主机的地址类型AF_INET*/

inth_length;/*主机的地址长度对于IP4是4字节32位*/

char**h_addr_list;/*主机的IP地址列表*/

}

#defineh_addrh_addr_list[0]/*主机的第一个IP地址*/

gethostbyname可以将机器名(如)转换为一个结构指针.在这个结构里面储存了域名的信息

gethostbyaddr可以将一个32位的IP地址(C0A80001)转换为结构指针.

这两个函数失败时返回NULL且设置h_errno错误变量,调用h_strerror()可以得到详细的出错信息

3.3字符串的IP和32位的IP转换.

在网络上面我们用的IP都是数字加点(192.168.0.1)构成的,而在structin_addr结构中用的是32位的IP,

我们上面那个32位IP(C0A80001)是的192.168.0.1为了转换我们可以使用下面两个函数

intinet_aton(constchar*cp,structin_addr*inp)

char*inet_ntoa(structin_addrin)

函数里面a代表asciin代表network.第一个函数表示将a.b.c.d的IP转换为32位的IP,

存储在inp指针里面.第二个是将32位IP转换为a.b.c.d的格式.

3.4服务信息函数

在网络程序里面我们有时候需要知道端口.IP和服务信息.这个时候我们可以使用以下几个函数

intgetsockname(intsockfd,structsockaddr*localaddr,int*addrlen)

intgetpeername(intsockfd,structsockaddr*peeraddr,int*addrlen)

structservent*getservbyname(constchar*servname,constchar*protoname)

structservent*getservbyport(intport,constchar*protoname)

structservent

{

char*s_name;/*正式服务名*/

char**s_aliases;/*别名列表*/

ints_port;/*端口号*/

char*s_proto;/*使用的协议*/

}

一般我们很少用这几个函数.对应客户端,当我们要得到连接的端口号时在connect调用成功后使用可得到

系统分配的端口号.对于服务端,我们用INADDR_ANY填充后,为了得到连接的IP我们可以在accept调用成功后使用而得到IP地址.

在网络上有许多的默认端口和服务,比如端口21对ftp80对应WWW.为了得到指定的端口号的服务我们可以调用第四个函数,

相反为了得到端口号可以调用第三个函数.

3.5一个例子

CODE:

[Copytoclipboard]

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

intmain(intargc,char**argv)

{

structsockaddr_inaddr;

structhostent*host;

char**alias;

if(argc<2)

{

fprintf(stderr,"Usage:

%shostname|ip..\n\a",argv[0]);

exit

(1);

}

argv++;

for(;*argv!

=NULL;argv++)

{

/*这里我们假设是IP*/

if(inet_aton(*argv,&addr.sin_addr)!

=0)

{

host=gethostbyaddr((char*)&addr.sin_addr,4,AF_INET);

printf("AddressinformationofIp%s\n",*argv);

}

else

{

/*失败,难道是域名?

*/

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工作范文 > 制度规范

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1