It计算机课件 Linu-TCP-IP网络编程_第1页
It计算机课件 Linu-TCP-IP网络编程_第2页
It计算机课件 Linu-TCP-IP网络编程_第3页
It计算机课件 Linu-TCP-IP网络编程_第4页
It计算机课件 Linu-TCP-IP网络编程_第5页
已阅读5页,还剩126页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

-rLINUX网辂编程

LINUXTCP/IP网络编程

3匚大,堂信息科考与工程学院付冲

LINUX网辂编程

LinuxTCP/IP网络编程

1.1Linux网络基础

TCP/IP协议集

TELNETFTPSMTPDNSHTTPSNMPPOPApplication

TCPUDPTransport

ICMP

IPInternet

ARPRARP

Host-to-

ARPANETSATNETPacketradioLAN

network

LINUX网辂编程

L本地回路:lo,固定IP地址:

以太网卡:ethO,ethl,.......

2.查看IP地址一ifconfig

各字段说明:

Hwaddr:网卡地址(物理地址,硬件地址)

inetaddr:IP地址

Beast:广播地址

LINUX网辂编程

Mask:子网掩码

MTU:MaxTransmissionUnit,最大传输单元,

即数据帧最大长度

Metric:路由长度

TXpackets:发送的数据包总数、错误数、遗失数

及溢出数

RXpackets:接收的数据包总数、错误数、遗失数

及溢出数

LINUX网辂编程

3.设置IP地址相关信息

语法:ifconfig接口IP地址[broadcast广播

地址netmask子网掩码]

例:ifconfigethO

ifconfigethObroadcast

55netmask

注意:ifconfig命令设置的IP地址不能永久保存,重

新启动计算机后将丢失设置

LINUX网辂编程

4.netconfig命令设置网络参数

usedynamicIPconfiguration

IPaddress

Netmask

Defaultgateway(IP)

Primarynameserver

注意:netconfig命令设置的网络配置信息可以永久

保存到配置文件中,但不会立即生效,刷新方

法:/etc/init.d/networkrestart

LINUX网辂编程

5.网络配置相关文件

(1)/etc/sysconfig/network

HOSTNAME:主机名设置

GATEWAY:默认网关的设置

LINUX网辂编程

(2)/etc/sysconng/network-scnpts/ifcfg-ethO

DEVICE:设备名称

BOOTPROTO:IP地址设置方式(动态或静态)

BROADCAST:广播地址

HWADDR:硬件地址

IPADDR:IP地址设置

NETMASK:子网掩码设置

NETWORK:网络地址

ONBOOT:启动时是否激活

LINUX网辂编程

(3)/etc/resolv.conf

DNS服务器地址设置。

(4)/etc/hosts

存放一些常用主机的IP地址与主机名称的数据,

即一个简单的DNS数据库。

基本格式为:

IP主机域名主机别名

(5)/etc/services

记录主机提供的网络服务项目、端口号(port)及

使用的运输层协议。

LINUX网辂编程

1.2套接字编程基本概念

在UNIX系统中,网络应用编程接口有两类:

UNIXBSD的套接字(socket)

UNIXSystemV的TLI

由于Sim公司采用了支持TCP/IP的UNIXBSD操

作系统,使TCP/IP的应用有更大的发展,其网络应

用编程接口---套接字(socket)在网络软件中被广泛应

用,至今已引进微机操作系统DOS和Windows系统

中,成为开发网络应用软件的强有力工具。

LINUX网辂编程

1.2.1网间进程通信

进程通信的概念最初来源于单机系统。由于每个进

程都在自己的地址范围内运行,为保证两个相互通信

的进程之间既互不干扰又协调一致工作,操作系统为进

程通信提供了相应设施,如UNIXBSD中的管道

(pipe)、命名管道(namedpipe)和软中断信号(signal),

UNIXsystemV的消息(message)、共享存储区(shared

memory)和信号量(semaphore)等,但都仅限于用在本

机进程之间通信。

LINUX网辂编程

网间进程通信要解决的是不同主机进程间的相互通信问

题。

为此,首先要解决的是网间进程标识问题。同一主机

上,不同进程可用进程号(processID)唯一标识。但

在网络环境下,各主机独立分配的进程号不能唯一标识

该进程。例如,主机A赋于某进程号5,在B机中也可

以存在5号进程,因此,“5号进程”这句话就没有意义

了。

其次,操作系统支持的网络协议众多,不同协议的工

作方式不同,地址格式也不同。

LINUX网辂编程

因此,网间进程通信还要解决多重协议的识别问

题。

为了解决上述问题,TCP/IP协议引入了下列几个概

念。

⑴端口

网络中可以被命名和寻址的通信端口,是操作系

统可分配的一种资源。

LINUX网辂编程

按照OSI七层协议的描述,运输层与网络层在功能

上的最大区别是运输层提供进程通信能力。从这个意

义上讲,网络通信的最终地址就不仅仅是主机地址

了,还包括可以描述进程的某种标识符。为此,

TCP/IP协议提出了协议端口(protocolport),简称端

口)的概念,用于标识通信的进程。

端口是一种抽象的软件结构(包括一些数据结构和

DO缓冲区)。

LINUX网辂编程

应用程序(即进程)通过系统调用与某端口建立连接

(binding)后,运输层传给该端口的数据都被相应进程

所接收,相应进程发给运输层的数据都通过该端口输

出。

在TCP/IP协议的实现中,端口操作类似于一般的

DO操作,进程获取一个端口,相当于获取本地唯一的

DO文件,可以用一般的读写原语访问之。

LINUX网辂编程

类似于文件描述符,每个端口都拥有一个叫端口号

(portnumber)的整数型标识符,用于区别不同端口。

由于TCP/IP运输层的两个协议TCP和UDP是完全独立

的两个软件模块,因此各自的端口号也相互独立,如

TCP有一个255号端口,UDP也可以有一个255号端

口,二者并不冲突。

LINUX网辂编程

TCP/IP号端口号分为两部分,少量的作为保留端

口,以全局方式分配给服务进程。因此,每一个标准

服务器都拥有一个全局公认的端口(即周知端口,

well-knownport),即使在不同机器上,其端口号也

相同。剩余的为自由端口,以本地方式进行分配。

TCP和UDP均规定,小于256的端口号才能作保留端

口八

LINUX网辂编程

⑵地址

网络通信中通信的两个进程分别在不同的机器上。

在互连网络中,两台机器可能位于不同的网络,这些

网络通过网络互连设备(网关,网桥,路由器等)连

接。因此需要三级寻址:

(a)某一主机可与多个网络相连,必须指定一特定网络

地址;

LINUX网辂编程

(b)网络上母一台主机应有其唯一的地址;

(c)每一主机上的每一进程应有在该主机上的唯一标识

符。

通常主机地址由网络ID和主机ID组成,在TCP/IP

协议中用32位整数值表示;TCP和UDP均使用16位

端口号标识用户进程。

LINUX网辂编程

(3)网络字节顺序

不同的计算机存放多字节值的顺序不同,有的机器

在起始地址存放低位字节(低位先存),有的存高位

字节(高位先存)。为保证数据的正确性,在网络协

议中须指定网络字节顺序。TCP/IP协议使用16位整数

和32位整数的高位先存格式,它们均含在协议头文件

中。

LINUX网辂编程

(4)半相关

综上所述,网络中用一个三元组可以在全局唯一标

志一个进程:

(协议,本地地址,本地端口号)

这样一个三元组,叫做一个半相关(half-

association),它指定连接的每半部分。

LINUX网辂编程

(5)全相关

一个完整的网间进程通信需要由两个进程组成,并

且只能使用同一种高层协议。也就是说,不可能通信

的一端用TCP协议,而另一端用UDP协议。因此一

个完整的网间通信需要一个五元组来标识:

(协议,本地地址,本地端口号,远地地址,远地端口

号)

LINUX网辂编程

这样一个五元组,叫做一个相关(association),即两

个协议相同的半相关才能组合成一个合适的相关,或

完全指定组成一连接。

LINUX网辂编程

1.2.2客户/服务器模式

在TCP/IP网络应用中,通信的两个进程间相互作

用的主要模式是客户/服务器模式(Client/Server

model),即客户向服务器发出服务请求,服务器接收

到请求后,提供相应的服务。

客户/服务器模式的建立基于以下两点:首先,建立

网络的起因是网络中软硬件资源、运算能力和信息不

均等,需要共享,从而造就拥有众多资源的主机提供

服务,资源较少的客户请求服务这一非对等作用。

LINUX网辂编程

其次,网间进程通信完全是异步的,相互通信的进

程间既不存在父子关系,又不共享内存缓冲区,因此

需要一种机制为希望通信的进程间建立联系,为二者

的数据交换提供同步,这就是基于客户/服务器模式的

TCP/IPo

LINUX网辂编程

客户/服务器模式在操作过程中采取的是主动请求方

式:

首先服务器方要先启动,并根据请求提供相应服

务:

(1)打开一通信通道并告知本地主机,它愿意在某

一公认地址上(周知口,如FTP为21)接收客户请求;

(2)等待客户请求到达该端口;

LINUX网辂编程

(3)接收到重复服务请求,处理该请求并发送应答信

号。接收到并发服务请求,要激活一新进程来处理这

个客户请求(如UNIX系统中用fork,exec)。新进程处

理此客户请求,并不需要对其它请求作出应答。服务

完成后,关闭此新进程与客户的通信链路,并终止。

(4)返回第二步,等待另一客户请求。

(5)关闭服务器。

LINUX网辂编程

客户方:

1.打开一通信通道,并连接到服务器所在主机的

特定端口;

2.向服务器发服务请求报文,等待并接收应答;

继续提出请求……

3.请求结束后关闭通信通道并终止。

LINUX网辂编程

从上面所描述过程可知:

1.客户与服务器进程的作用是非对称的,因此编码

不同。

2.服务进程一般是先于客户请求而启动的。只要系

统运行,该服务进程一直存在,直到正常或强迫终

止。

LINUX网辂编程

1.2.3套接字类型

TCP/IP的socket提供下列三种类型套接字。

1.流式套接字(SOCK_STREAM)

提供了一个面向连接、可靠的数据传输服务,数据

无差错、无重复地发送,且按发送顺序接收。内设流

量控制,避免数据流超限;数据被看作是字节流,无

长度限制。文件传送协议(FTP)即使用流式套接字。

LINUX网辂编程

2.数据报式套接字(SOCK_DGRAM)

提供了一个无连接服务。数据包以独立包形式被发

送,不提供无错保证,数据可能丢失或重复,并且接

收顺序混乱。网络文件系统(NFS)使用数据报式套接

字。

3.原始式套接字(SOCK_RAW)

该接口允许对较低层协议,如IP、ICMP直接访问。

常用于检验新的协议实现或访问现有服务中配置的新

设备。

LINUX网辂编程

1.3基本套接字系统调用

为了更好地说明套接字编程原理,下面给出几个基

本套接字系统调用说明。

1.3.1创建套接字——socket()

应用程序在使用套接字前,首先必须拥有一个套接

字,系统调用socket。向应用程序提供创建套接字的手

段,其调用格式如下:

LINUX网辂编程

mtsocket(mtdomain,mttype,intprotocol)

domain:说明我们网络程序所在的主机采用的通信

协议族(AFJJNIX和AFJNET等).UNIX系统支持的地

址族有:AFJJNIX、AFJNET>AF_NS等,而DOS、

WINDOWS中仅支持AF_INET,它是网际网区域。

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

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

之间通信。

LINUX网辂编程

type:网络程序所采用的通信协议(SOCK_STREAM,

SOCK_DGRAM等)。

SOCK_STREAM表明采用的是TCP协议,即提供

按顺序的,可靠,双向,面向连接的比特流。

SOCK_DGRAM表明采用的是UDP协议,这样只

会提供定长的,不可靠,无连接的通信。

LINUX网辂编程

protocol:由于我们指定了type,所以这个地方我们一

般只要用0来代替就可以了socket为网络通信做基本

的准备.

成功时返回文件描述符,失败时返回查看errno可

知道出错的详细情况.

根据这三个参数建立一个套接字,并将相应的资源

分配给它,同时返回一个整型套接字号。

因此,socket。系统调用实际上指定了相关五元组中

的“协议”这一元。

LINUX网辂编程

1.3.2指定本地地址——bind()

当一个套接字用socket。创建后,存在一个名字空间

(地址族),但它没有被命名。bind。将套接字地址(包括

本地主机地址和本地端口地址)与所创建的套接字号

联系起来,即将名字赋予套接字,以指定本地半相

关。其调用格式如下:

LINUX网辂编程

mtbind(mtsockfd,structsockaddr*my_addr,mt

addrlen)

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

addrlen:是sockaddr结构的长度.

my_addr:是一个指向sockaddr的指针.

sockaddr的定义:

LINUX网辂编程

structsockaddr{

unisgnedshortas_family;

charsa_data[14];

);

不过由于系统的兼容性,我们一般使用另外一个结构

(structsockaddr_in)来代替.

sockaddr_in的定义:

LINUX网辂编程

structsockaddr_in{

shortsin_family;

u_shortsin_port;/*16位端口号,网络字节顺序*/

structin_addrsin_addr;/*32位IP地址,网络字节顺序刃

charsin_zero[8];/*保留刃

)

我们主要使用Internet所以sin_family一般为AF_INET,

sinaddr设置为INADDRANY表示可以和任何的主机

LINUX网辂编程

通信,sin_port是我们要监听的端口号.sin_zero⑻是用

来填充的.bind1寻本地的端口同socket返回的文件描述

符捆绑在一起.成功是返回0,失败的情况和socket一

样。

LINUX网辂编程

1.3.3建立套接字连接一connect()与accept()

这两个系统调用用于完成一个完整相关的建立,其中

connect。用于建立连接。无连接的套接字进程也可以调

用connect(),但这时在进程之间没有实际的报文交换,

调用将从本地操作系统直接返回。而accept。用于使服

务器等待来自某客户进程的实际连接。

connect。的调用格式如下:

intconnect(intsockfd,structsockaddr^serv_addr9int

addrlen)

LINUX网辂编程

参数sockfd是欲建立连接的本地套接字描述符。参

数serv_addr指出说明对方套接字地址结构的指针。

对方套接字地址长度由addrlen说明。

connect函数是客户端用来同服务端连接的。成功时

返回0,sockfd是同服务端通信的文件描述符,失败时

返回

LINUX网辂编程

accept。的调用格式如下:

intaccept(intsockfd,structsockaddr*addr,int

^addrlen)

accept()调用前应该先调用过listen()o

sockfd:是listen后的文件描述符。

addr,addrlen是用来给客户端的程序填写的,服务

器端只要传递指针就可以了。

LINUX网辂编程

调用前,参数addr指向一个初始值为空的地址结

构,而addrlen的初始值为0;调用accept()后,服务

器等待从编号为sockfd的套接字上接受客户连接请

求,而连接请求是由客户方的connect()调用发出的。

当有连接请求到达时,accept()调用将请求连接队列上

的第一个客户方套接字地址及长度放入addr和addrlen.

LINUX网辂编程

bind,listen和accept是服务器端用的函数,accept调

用时,服务器端的程序会一直阻塞到有一个客户程序发

出了连接。accept成功时返回最后的服务器端的文件

描述符,这个时候服务器端可以向该描述符写信息

了,失败时返回4。

四个套接字系统调用,socket。、bind。、connect。、

accept(),可以完成一个完全五元相关的建立。socket()

指定五元组中的协议元,它的用法与是否为客户或服

务器、是否面向连接无关。

LINUX网辂编程

bind()指定五元组中的本地二元,即本地主机地址和

端口号,其用法与是否面向连接有关:在服务器方,

无论是否面向连接,均要调用bind。;在客户方,若采

用面向连接,则可以不调用bind(),而通过connect。自

动完成。若采用无连接,客户方必须使用bind。以获得

一个唯一的地址。

LINUX网辂编程

1.3.4监听连接——listen()

此调用用于面向连接服务器,表明它愿意接收连

接。listen。需在accept。之前调用,其调用格式如下:

intlisten(intsockfd,intbacklog)

参数sockfd标识一个本地已建立、尚未连接的套接

字号,服务器愿意从它上面接收请求。

LINUX网辂编程

backlog表示请求连接队列的最大长度,用于限制排

队请求的个数,目前允许的最大值为5。如果没有错误

发生,listen。返回0。否则它返回SOCKET_ERROR。

调用listen。是服务器接收一个连接请求的四个步骤

中的第三步。它在调用socket。分配一个流套接字,且

调用bind。给sockfd赋于一个名字之后调用,而且一

定要在accept。之前调用。

LINUX网辂编程

在客户/服务器模式中,有两种类型的服务:重复服

务和并发服务。accept。调用为实现并发服务提供了极

大方便,因为它要返回一个新的套接字号,其典型结

构为:

intinitsockid,newsockid;

if((initsockid=socket(....))<0)

error(ucan,tcreatesocket");

if(bind(initsockidv...)<0)

error(ubinderror");

LINUX网辂编程

if(listen(initsockid,5)v0)

error(ulistenerror");

for(;;){

newsockid=accept(initsockid,)/*阻塞*/

if(newsockid<0)

error(uaccepterror");

if(fork()==0){/*子进程*/

closesocket(initsockid);

do(newsockid);/*处理请求*/

exit(0);

LINUX网辂编程

closesocket(newsockid);/*父进程*/

)

这段程序执行的结果是newsockid与客户的套接字建

立相关,子进程启动后,关闭继承下来的主服务器的

initsockid,并利用新的newsockid与客户通信。主服务

器的initsockid可继续等待新的客户连接请求。由于在

Unix等抢先多任务系统中,在系统调度下,多个进程

可以同时进行。因此,使用并发服务器可以使服务器

LINUX网辂编程

进程在同一时间可以有多个子进程和不同的客户程序

连接、通信。在客户程序看来,服务器可以同时并发

地处理多个客户的请求,这就是并发服务器名称的来

由。

LINUX网辂编程

面向连接服务器也可以是重复服务器,其结构如下:

intinitsockid,newsockid;

if((initsockid=socket(....))<0)

error(ucan,tcreatesocket");

if(bind(initsockidv...)<0)

error(ubinderror");

if(listen(initsockid,5)<0)

error(ulistenerror");

LINUX网辂编程

for(;;){

newsockid=accept(initsockid,...)/*阻塞❖/

if(newsockid<0)

error(uaccepterror");

do(newsockid);/*处理请求*/

closesocket(newsockid);

)

LINUX网辂编程

重复服务器在一个时间只能和一个客户程序建立连

接,它对多个客户程序的处理是采用循环的方式重复

进行,因此叫重复服务器。

并发服务器和重复服务器各有利弊:并发服务器可

以改善客户程序的响应速度,但它增加了系统调度的

开销;重复服务器正好与其相反,因此用户在决定是

使用并发服务器还是重复服务器时,要根据应用的实

际情况来定。

服务器方

LINUX网辂编程

客户机方

建立连接

服务请求/应答

LINUX网辂编程

1.4基本套接字通信程序实例

服务器端(server-basic.c):

#include<stdio.h>

#include<errno.h>

#include<netdb.h>

#include<sys/socket.h>

intmain(intargc,char*argv[]){

intsockfd,new_fd;

structsockaddr_inserver_addr;

structsockaddr_inclient_addr;

LINUX网辂编程

intsin_size,portnumber;

charhello[]=HHello!AreYouFine?\nM;

if(argc!=2){

H1f

fprintf(stderr9Usage:%sportnumber\a\n,argv[0]);

exit(l);

)

if((portnumber=atoi(argv[l]))<0){

n1

fprintf(stderr9Usage:%sportnumber\a\n,argv[0]);

exit(l);

LINUX网辂编程

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

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

(

fprintf(stderr,nSocketerror:%s\n\a,\strerror(errno));

exit(l);

)

/*服务器端填充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);

LINUX网辂编程

/*捆绑sockfd描述符*/

if(bind(sockfd,(structsockaddr*)(&server_addr),

sizeof(structsockaddr))==-1){

fprintf(stderr,nBinderror:%s\n\a*\strerror(errno));

exit(l);

)

/*监听sockfd描述符*/

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

Hn

fprintf(stderr,Listenerror:%s\n\a9strerror(errno));

LINUX网辂编程

exit(l);

)

\¥11阳1){

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

sin_size=sizeof(structsockaddr_in);

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

&sin_size))==-1)

Hn

fprintf(stderr,Accepterror:%s\n\a9strerror(errno));

exit(l);

LINUX网辂编程

fprintf(stderr,HServergetconnectionfrom%s\nH,

inet_ntoa(client_addr.sin_addr));

if(write(new_fd,hello,strlen(hello))==-l){

Mn

fprintf(stderr,WriteError:%s\n9strerror(errno));

exit(l);

)

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

close(new_fd);

/*循环下一^个*/

LINUX网辂编程

close(sockfd);

exit(O);

)

客户端(client-basic・c):

#include<stdio.h>

#include<netdb.h>

#include<sys/socket.h>

#include<sys/errno.h>

intmain(intargc,char*argv口)

LINUX网辂编程

mtsockfd;

charbuffer[1024];

structsockaddr_inserver_addr;

structhostent*host;

intportnumber,nbytes;

if(argc!=3){

n1

fprintf(stderr9Usage:%shostnameportnumber\a\n*,

argv[0]);

exit(l);

LINUX网辂编程

if((host=gethostbyname(argv[l]))==NULL){

fprintf(stderr,nGethostnameerror\nn);

exit(l);

)

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

fprintf(stderr,HUsage:%shostnameportnumber\a\n1*,

argv[0]);

exit(l);

)

LINUX网辂编程

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

if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-l){

M

fprintf(stderr9^SocketError:%s\a\n,strerror(errno));

exit(l);

)

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

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);

LINUX网辂编程

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

if(connect(sockfd,(structsockaddr*)(&server_addr),

sizeof(structsockaddr))==-1){

fprintf(stderr,nConnectError:%s\a\nf\strerror(errno));

exit(l);

)

/*连接成功*/

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

fprintf(stderr,nReadError:%s\nf\strerror(errno));

exit(l);

LINUX网辂编程

buffer[nbytes]=H\On;

printf(MIhavereceived:%s\nf\buffer);

/*结束通信*/

close(sockfd);

exit(O);

LINUX网辂编程

1.5服务器和客户机的信息函数

1.5.1字节转换函数

在网络上面有着许多类型的机器,这些机器在表示数

据的字节顺序是不同的,比如i386芯片是低字节在内存

地址的低端,高字节在高端,而alpha芯片却相反.为了

统一起来在Linux下面,有专门的字节转换函数.

LINUX网辂编程

unsignedlongmthtonl(unsignedlongmthostlong)

unsignedshortinthtons(unisgnedshortinthostshort)

unsignedlongintntohl(unsignedlongintnetlong)

unsignedshortintntohs(unsignedshortintnetshort)

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

代表short,1代表long,第一个函数的意义是将本机器

上的long数据转化为网络上的long.其他几个函数的意

义同上.

LINUX网辂编程

1.5.2IP和域名的转换

在网络上标志一台机器可以用IP或者是用域名,那

么我们怎么去进行转换呢?

structhostent*gethostbyname(constchar*hostname)

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

structhostent的定义:

LINUX网辂编程

structhostent{

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

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

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

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

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

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

)

gethostbyname可以将机器名(如)#

换为一个结构指针.在这个结构里面储存了域名的信息.

LINUX网辂编程

gethostbyaddr可以将一个32位的IP地址(C0A80001)

转换为结构指针.

这两个函数失败时返回NULL且设置h_errno错误

变量,调用h_strerror()可以得到详细的出错信息.

1.5.3字符串的IP和32位IP的转换

在网络上面我们用的IP都是数字加点()

构成的,而在structin_addr结构中用的是32位的IP,

我们上面那个32位IP(C0A80001)是的,为

了转换我们可以使用下面两个函数

LINUX网辂编程

mtmet_aton(constchar*cp,structm_addr*mp)

char^inet_ntoa(structin_addrin)

函数里面a代表asciin代表network.第一个函数表

示将a.b.c.d的IP转换为32位的IP,存储在inp指针里

面.第二个是修32位IP转换为a.b.c.d的格式.

LINUX网辂编程

1.6完整的读写函数

在Linux中把我们前面建立的通道看成是文件描述

符,这样服务器端和客户端进行通信时候,只要往文件描

述符里面读写东西了.就象我们往文件读写一样.

1.6.1写函数write

intwrite(intfd,constvoid*buf,size_tnbytes)

write函数将buf中的nbytes字节内容写入文件描述

符fd.成功时返回写的字节数.失败时返回并设置

errno变量.

LINUX网辂编程

在网络程序中,当我们向套接字文件描述符写时有两

种可能.

(1)write的返回值大于0,表示写了部分或者是全部的

数据.

(2)返回的值小于0,此时出现了错误.我们要根据错误

类型来处理.

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

LINUX网辂编程

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

关闭了连接).

1.6.2读函数read

intread(intfd,void*buf,size_tnbyte)

read函数是负责从fd中读取内容.当读成功时,read

返回实际所读的字节数,如果返回的值是0表示已经读

到文件的结束了,小于0表示出现了错误.如果错误为

EINTR说明读是由中断引起的,如果是ECONNREST

表示网络连接出了问题.

LINUX网辂编程

1.6.3send()与recv()

send和recv函数提供了和read和write差不多的功

能.

send()调用用于在参数s指定的已连接的数据报或流

套接字上发送输出数据,格式如下:

intsend(intsockfd,void*buf,intlen,intflags)

参数sockfd为已连接的本地套接字描述符。buf指

向存有发送数据的缓冲区的指针,其长度由len指定。

flags指定传输控制方式,如是否发送带外数据等。

LINUX网辂编程

如果没有错误发生,send。返回总共发送的字节数。否

则它返回SOCKET_ERROR。

recv()调用用于在参数sockfd指定的已连接的数据

报或流套接字上接收输入数据,格式如下:

intrecv(intsockfd,void*buf,intleu,intflags)

参数sockfd为已连接的套接字描述符。Buf指向接收

输入数据缓冲区的指针,其长度由len指定。flags指

定传输控制方式,如是否接收带外数据等。

LINUX网辂编程

如果没有错误发生,recv()返回总共接收的字节数。如

果连接被关闭,返回0。否则它返回

SOCKETERRORo

LINUX网辂编程

1.6.4关闭套接字——close()

closesocket()关闭套接字sockfd,并释放分配给该套

接字的资源;如果sockfd涉及一个打开的TCP连接,

则该连接被释放。dosesocket。的调用格式如下:

intclose(intsockfd)

参数sockfd为待关闭的套接字描述符。如果没有错

误发生,closesocket()返回0。否则返回值

SOCKETERRORo

LINUX网辂编程

1.7完整的数据收发与套接字关闭程序

服务器端(server-standard.c):

#include<stdio.h>

#include<errno.h>

#include<netdb.h>

#include<sys/socket.h>

intmain(intargc,char*argv[])

intsockfd,new_fd;

structsockaddr_inserver_addr;

structsockaddr_inclient_addr;

LINUX网辂编程

intsin_size,portnumber;

charhello[]=HHello!AreYouFine?\nM;

if(argc!=2)

(

H1

fprintf(stderr9Usage:%sportnumber\a\n*,argv[0]);

exit(l);

)

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

(

fprintf(stderr,MUsage:%sportnumber\a\n1,argv[0]);

exit(l);

)

LINUX网辂编程

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

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

(

fprintf(stderr,nSocketerror:%s\n\a,\strerror(errno));

exit(l);

)

/*服务器端填充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);

LINUX网辂编程

/*捆绑sockfd描述符*/

if(bind(sockfd,(structsockaddr*)(&server_addr)9sizeof(struct

sockaddr))==-1)

(

Kn

fprintf(stderr,Bmderror:%s\n\a9strerror(errno));

exit(l);

)

/*监听sockfd描述符*/

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

fprintf(stderr,^Listenerror:%s\n\a,\strerror(errno));

LINUX网辂编程

exit(l);

)

\¥11阳1){

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

sin_size=sizeof(structsockaddr_in);

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

&sin_size))==-1)

Hn

fprintf(stderr,Accepterror:%s\n\a9strerror(errno));

exit(l);

LINUX网辂编程

fprintf(stderr,HServergetconnectionfrom

inet_ntoa(client_addr.sin_addr));

if(write(new_fd,hello,strlen(hello))==-l){

1n

fprintf(stderr,,WriteError:%s\n9strerror(errno));

exit(l);

)

while(l)

intflag;

LINUX网辂编程

if((flag=read(new_fd,buf,1024))<0)

(

printf(nReadingdataerror!\nn);

break;

)

if(flag==0)

(

printf(MEndingcurrentconnection!\nH);

break;

)

else

LINUX网辂编程

prmtf(—>%s\n\buf);

if(strstr(buf,nexitn)){

printf(HEndingcurrentconnection!\nM);

break;

)

//if(strstr(buf,nbyen))

//{

//close(new_fd);

//close(sockfd);

//exit(O);

//)

LINUX网辂编程

}//else

}//while

close(new_fd);

}//while

close(sockfd);

exit(O);

LINUX网辂编程

客户端(client.standard.c):

#include<stdio.h>

#include<netdb.h>

#include<sys/socket.h>

#include<sys/errno.h>

intmain(intargc,char*argv[]){

LINUX网辂编程

mtsockfd;

charbuffer[1024];

structsockaddr_inserver_addr;

structhostent*host;

intportnumber,nbytes;

if(argc!=3)

(

fprintf(stderr,HUsage:%shostnameportnumber\a\n1,

argv[0]);

exit(l);

LINUX网辂编程

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

(

fprintf(stderr,"Gethostnameerror\nM);

exit(l);

)

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

(

n1

fprintf(stderr9Usage:%shostnameportnumber\a\n*,

argv[0]);

exit(l);

LINUX网辂编程

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

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

(

nf

fprintf(stderr9SocketError:%s\a\n\strerror(errno));

exit(l);

)

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

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);

LINUX网辂编程

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

if(connect(sockfd,(structsockaddr*)(&server_addr),

sizeof(structsockaddr))==-1)

(

nn

fprintf(stderr,ConnectError:%s\a\n9strerror(errno));

exit(l);

)

/*连接成功了*/

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

LINUX网辂编程

fprintf(stderr,HReadError:%s\n,\strerror(errno));

exit(l);

)

buffer[nbytes]=**\0n;

Mn

printf(Ihavereceived:%s\n9buffer);

while(l)

gets(buffer);

if(wri阳sockfd,buffer,sizeof(buffer))<0)

printf(Msendingdataerror!\nn);

LINUX网辂编程

if(strstr(buffer,exitn))

break;

)

/*结束通信*/

close(sockfd);

exit(O);

LINUX网辂编程

1.8完整的多进程套接字通信程序

月艮务器端(server-advance.c):

#include<stdio.h>

#include<errno.h>

#include<netdb.h>

#include<sys/socket.h>

//maybeusebygetpid()andgetppid()

#include<unistd.h>

intmain(intargc,char*argv[])

LINUX网辂编程

intsockfd,new_fd;

structsockaddr_inserver_addr;

structsockaddr_inclient_addr;

intsin_size,portnumber;

charhello[]=nHello!AreYouFine?'';

charbuf[1024];

intflag;

if(argc!=2)

M11

fprintf(stderr9Usage:%sportnumber\a\n,argv[0]);

exit(l);

LINUX网辂编程

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

(

fprintf(stderr,nUsage:%sportnumber\a\n1*,argv[O]);

exit(l);

)

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

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

nM

fprintf(stderr,Socketerror:%s\n\a9strerror(errno));

exit(l);

LINUX网辂编程

/*服务器立而填充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(struct

sockaddr))=="l)

(

fprintf(stderr,HBmderror:%s\n\af\strerror(errno));

exit(l);

)

LINUX网辂编程

/*监听sockfd描述符*/

if(listen(sockfd95)==-1)

(

fprintf(stderr,HListenerror:%s\n\af\strerror(errno));

exit(l);

)

//printfmyPIDnum

printf(nStartingServeratport:%dSuccess.MyPIDis:%d\n

AcceptingRequest…\n'',portnumber,getpid());

while(l)

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

LINUX网辂编程

sin_size=sizeof(structsockaddr_in);

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

&sin_size))=="l)

(

fprintf(stderr,nAc

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论