Board logo

标题: [转帖]SOCKET编程的基本概念 [打印本页]

作者: 凉心无悔    时间: 2005-5-14 21:06     标题: [转帖]SOCKET编程的基本概念

socket编程的基本概念- -
                                       
在开始使用套接字编程之前,首先必须建立以下概念。
1  网间进程通信
       进程通信的概念最初来源于单机系统。由于每个进程都在自己的地址范围内运行,为保证两个相互通信的进程之间既互不干扰又协调一致工作,操作系统为进程通信提供了相应设施,如UNIX  BSD中的管道(pipe)、命名管道(named pipe)和软中断信号(signal),UNIX system V的消息(message)、共享存储区(shared memory)和信号量(semaphore)等,但都仅限于用在本机进程之间通信。网间进程通信要解决的是不同主机进程间的相互通信问题(可把同机进程通信看作是其中的特例)。为此,首先要解决的是网间进程标识问题。同一主机上,不同进程可用进程号(process ID)唯一标识。但在网络环境下,各主机独立分配的进程号不能唯一标识该进程。例如,主机A赋于某进程号5,在B机中也可以存在5号进程,因此,“5号进程”这句话就没有意义了。
       其次,操作系统支持的网络协议众多,不同协议的工作方式不同,地址格式也不同。因此,网间进程通信还要解决多重协议的识别问题。
       为了解决上述问题,TCP/IP协议引入了下列几个概念。
端口
       网络中可以被命名和寻址的通信端口,是操作系统可分配的一种资源。
       按照OSI七层协议的描述,传输层与网络层在功能上的最大区别是传输层提供进程通信能力。从这个意义上讲,网络通信的最终地址就不仅仅是主机地址了,还包括可以描述进程的某种标识符。为此,TCP/IP协议提出了协议端口(protocol port,简称端口)的概念,用于标识通信的进程。
       端口是一种抽象的软件结构(包括一些数据结构和I/O缓冲区)。应用程序(即进程)通过系统调用与某端口建立连接(binding)后,传输层传给该端口的数据都被相应进程所接收,相应进程发给传输层的数据都通过该端口输出。在TCP/IP协议的实现中,端口操作类似于一般的I/O操作,进程获取一个端口,相当于获取本地唯一的I/O文件,可以用一般的读写原语访问之。
       类似于文件描述符,每个端口都拥有一个叫端口号(port number)的整数型标识符,用于区别不同端口。由于TCP/IP传输层的两个协议TCP和UDP是完全独立的两个软件模块,因此各自的端口号也相互独立,如TCP有一个255号端口,UDP也可以有一个255号端口,二者并不冲突。
       端 口号的分配是一个重要问题。有两种基本分配方式:第一种叫全局分配,这是一种集中控制方式,由一个公认的中央机构根据用户需要进行统一分配,并将结果公布 于众。第二种是本地分配,又称动态连接,即进程需要访问传输层服务时,向本地操作系统提出申请,操作系统返回一个本地唯一的端口号,进程再通过合适的系统调用将自己与该端口号联系起来(绑扎)。TCP/IP端口号的分配中综合了上述两种方式。TCP/IP将端口号分为两部分,少量的作为保留端口,以全局方式分配给服务进程。因此,每一个标准服务器都拥有一个全局公认的端口(即周知口,well-known port),即使在不同机器上,其端口号也相同。剩余的为自由端口,以本地方式进行分配。TCP和UDP均规定,小于256的端口号才能作保留端口。
地址
       网络通信中通信的两个进程分别在不同的机器上。在互连网络中,两台机器可能位于不同的网络,这些网络通过网络互连设备(网关,网桥,路由器等)连接。因此需要三级寻址:
1. 某一主机可与多个网络相连,必须指定一特定网络地址;
2. 网络上每一台主机应有其唯一的地址;
3. 每一主机上的每一进程应有在该主机上的唯一标识符。
       通常主机地址由网络ID和主机ID组成,在TCP/IP协议中用32位整数值表示;TCP和UDP均使用16位端口号标识用户进程。
网络字节顺序
       不同的计算机存放多字节值的顺序不同,有的机器在起始地址存放低位字节(低价先存),有的存高位字节(高价先存)。为保证数据的正确性,在网络协议中须指定网络字节顺序。TCP/IP协议使用16位整数和32位整数的高价先存格式,它们均含在协议头文件中。
连接
       两个进程间的通信链路称为连接。连接在内部表现为一些缓冲区和一组协议机制,在外部表现出比无连接高的可靠性。
半相关
       综上所述,网络中用一个三元组可以在全局唯一标志一个进程:
              (协议,本地地址,本地端口号)
       这样一个三元组,叫做一个半相关(half-association),它指定连接的每半部分。
全相关
       一个完整的网间进程通信需要由两个进程组成,并且只能使用同一种高层协议。也就是说,不可能通信的一端用TCP协议,而另一端用UDP协议。因此一个完整的网间通信需要一个五元组来标识:
              (协议,本地地址,本地端口号,远地地址,远地端口号)
       这样一个五元组,叫做一个相关(association),即两个协议相同的半相关才能组合成一个合适的相关,或完全指定组成一连接。
2  服务方式
       在网络分层结构中,各层之间是严格单向依赖的,各层次的分工和协作集中体现在相邻层之间的界面上。“服务”是描述相邻层之间关系的抽象概念,即网络中各层向紧邻上层提供的一组操作。下层是服务提供者,上层是请求服务的用户。服务的表现形式是原语(primitive),如系统调用或库函数。系统调用是操作系统内核向网络应用程序或高层协议提供的服务原语。网络中的n层总要向n+1层提供比n-1层更完备的服务,否则n层就没有存在的价值。
       在OSI的术语中,网络层及其以下各层又称为通信子网,只提供点到点通信,没有程序或进程的概念。而传输层实现的是“端到端”通信,引进网间进程通信概念,同时也要解决差错控制,流量控制,数据排序(报文排序),连接管理等问题,为此提供不同的服务方式:
面向连接(虚电路)或无连接
       面向连接服务是电话系统服务模式的抽象,即每一次完整的数据传输都要经过建立连接,使用连接,终止连接的过程。在数据传输过程中,各数据分组不携带目的地址,而使用连接号(connect ID)。本质上,连接是一个管道,收发数据不但顺序一致,而且内容相同。TCP协议提供面向连接的虚电路。
       无连接服务是邮政系统服务的抽象,每个分组都携带完整的目的地址,各分组在系统中独立传送。无连接服务不能保证分组的先后顺序,不进行分组出错的恢复与重传,不保证传输的可靠性。UDP协议提供无连接的数据报服务。
       下面给出这两种服务的类型及应用中的例子:
服务类型
服     务
例     子

面向连接
可靠的报文流
可靠的字节流
不可靠的连接
文件传输(FTP)
远程登录(Telnet)
数字话音

无连接
不可靠的数据报
有确认的数据报
请求-应答
电子邮件(E-mail)
电子邮件中的挂号信
网络数据库查询

顺序
       在网络传输中,两个连续报文在端-端通信中可能经过不同路径,这样到达目的地时的顺序可能会与发送时不同。“顺序”是指接收数据顺序与发送数据顺序相同。TCP协议提供这项服务。
差错控制
       保证应用程序接收的数据无差错的一种机制。检查差错的方法一般是采用检验“检查和(Checksum)”的方法。而保证传送无差错的方法是双方采用确认应答技术。TCP协议提供这项服务。
流控制
       在数据传输过程中控制数据传输速率的一种机制,以保证数据不被丢失。TCP协议提供这项服务。
字节流
       字节流方式指的是仅把传输中的报文看作是一个字节序列,不提供数据流的任何边界。TCP协议提供字节流服务。
报文
       接收方要保存发送方的报文边界。UDP协议提供报文服务。
全双工/半双工
       端-端间数据同时以两个方向/一个方向传送。
缓存/带外数据
       在字节流服务中,由于没有报文边界,用户进程在某一时刻可以读或写任意数量的字节。为保证传输正确或采用有流控制的协议时,都要进行缓存。但对某些特殊的需求,如交互式应用程序,又会要求取消这种缓存。
       在数据传送过程中,希望不通过常规传输方式传送给用户以便及时处理的某一类信息,如UNIX系统的中断键(Delete或Control-c)、终端流控制符(Control-s和Control-q),称为带外数据。逻辑上看,好象用户进程使用了一个独立的通道传输这些数据。该通道与每对连接的流相联系。由于Berkeley Software Distribution中对带外数据的实现与RFC 1122中规定的Host Agreement不一致,为了将互操作中的问题减到最小,应用程序编写者除非与现有服务互操作时要求带外数据外,最好不使用它。
3  客户/服务器模式
       在TCP/IP网络应用中,通信的两个进程间相互作用的主要模式是客户/服务器模式(Client/Server model),即客户向服务器发出服务请求,服务器接收到请求后,提供相应的服务。客户/服务器模式的建立基于以下两点:首先,建立网络的起因是网络中软硬件资源、运算能力和信息不均等,需要共享,从而造就拥有众多资源的主机提供服务,资源较少 的客户请求服务这一非对等作用。其次,网间进程通信完全是异步的,相互通信的进程间既不存在父子关系,又不共享内存缓冲区,因此需要一种机制为希望通信的进程间建立联系,为二者的数据交换提供同步,这就是基于客户/服务器模式的TCP/IP。
       客户/服务器模式在操作过程中采取的是主动请求方式:
       首先服务器方要先启动,并根据请求提供相应服务:
1.           打开一通信通道并告知本地主机,它愿意在某一公认地址上(周知口,如FTP为21)接收客户请求;
2.         等待客户请求到达该端口;
3.         接收到重复服务请求,处理该请求并发送应答信号。接收到并发服务请求,要激活一新进程来处理这个客户请求(如UNIX系统中用fork、exec)。新进程处理此客户请求,并不需要对其它请求作出应答。服务完成后,关闭此新进程与客户的通信链路,并终止。
4.         返回第二步,等待另一客户请求。
5.         关闭服务器
       客户方:
1.         打开一通信通道,并连接到服务器所在主机的特定端口;
2.         向服务器发服务请求报文,等待并接收应答;继续提出请求......
3.         请求结束后关闭通信通道并终止。
       从上面所描述过程可知:
1.         客户与服务器进程的作用是非对称的,因此编码不同。
2.         服务进程一般是先于客户请求而启动的。只要系统运行,该服务进程一直存在,直到正常或强迫终止。
4  套接字类型
       TCP/IP的socket提供下列三种类型套接字。
流式套接字(SOCK_STREAM)
       提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复地发送,且按发送顺序接收。内设流量控制,避免数据流超限;数据被看作是字节流,无长度限制。文件传送协议(FTP)即使用流式套接字。
数据报式套接字(SOCK_DGRAM)
       提供了一个无连接服务。数据包以独立包形式被发送,不提供无错保证,数据可能丢失或重复,并且接收顺序混乱。网络文件系统(NFS)使用数据报式套接字。
原始式套接字(SOCK_RAW)
       该接口允许对较低层协议,如IP、ICMP直接访问。常用于检验新的协议实现或访问现有服务中配置的新设备

作者: 凉心无悔    时间: 2005-5-14 21:08     标题: [转帖]SOCKET编程的基本概念

socket 通讯的概念性过程
1.SOCKET 通讯TCP方式一般流程图
服务端                                                                             客户端
socket()                                                                           socket()            
       |                                                                                       |
       |-------------------------setsockopt()-----------------------|
       |                                                                                       |
   bind()                                                                             connect()
       |                                                                                       |
       |                                                                                       |
   listen()                                                                           recv()/send()/write()
       |
       |
  accept()
       |
       |
       |
recv()/send()/read()
setsockopt的可用level为SOL_SOCKET:
option为:SO_REUSEADDR  选项就是可以实现端口重绑定的
其他的选项可以使用也可以不用.
2.SOCKET 通讯UDP方式一般流程图
服务端                                                                             客户端
socket()                                                                           socket()            
       |                                                                                       |
       |-------------------------setsockopt()---------------------- |
       |                                                                                       |
   bind()                                                                          sendto()
       |                                                                                       
       |                                                                                    
recvfrom()
如果是广播,则
setsockopt的可用level为SOL_SOCKET:
option为:SO_BROADCAST  选项就是该SOCKET 是用于广播的.
sendto地址可以为:255.255.255.255 受限地址
                                netid.255.255  (B类地址)该网络号下所有子网
                                10.128.1.255 (B类地址)该1子网的广播
                                10.128.255.255 (B类地址)所有子网的广播
如果是多播,则
setsockopt的可用level为IPPROTO_IP:
1IP_ADD_MEMBERSHIP: 加入一个多播组
2IP_DROP_MEMBERSHIP: 离开一个多播组
3IP_MULTICAST_IF: 指定外出多播数据报的外出接口
4IP_MULTICAST_TTL: TTL数
5IP_MULTICAST_LOOP: 是否禁止回馈,我的理解是一台机器是否可以接收到自己发送的多播数据报
struct ip_mreq 为IP_ADD_MEMBERSHIP的数据结构!
   多播地址为224.0.0.0.1~239.255.255.255


作者: 凉心无悔    时间: 2005-5-14 21:08     标题: [转帖]SOCKET编程的基本概念

Socket的概念
日期:2004-10-17 18:35:42   来源:http://bbs.wanw.net   作者:blue  总浏览:42
       Mail、ftp、telnet、name和finger都是网络上的计算机提供的服务器(这些服务器均是软件)。 每种服务器都是在一个专用的公开的端口上提供的,通过连接到这些端口,客户程序就能够访问这 些服务器。这与现实生活是相似的——当需要干洗衣服的时候,找干洗店;当需要取钱的时候,去银 行,等等。除了专用于特定服务器的端口外,计算机还有其它的端口让程序员创建他们自己的服务 器。
端口一般是编号的,通过指定服务器的端口号,客户程序可以连接到该端口上。每种服务器或 端口要有特定的协议,为了让客户的请求能够被理解和响应,客户必须以这种服务器特有的方式形 成客户请求。
Socket是网络上运行的两个程序间双向通信连接的一端。Socket这个词的一般意义是自然的 或人工的插口,如家用电器的电源插口等。
客户程序可以向Socket写请求,服务器将处理此请求,然后通过Socket把结果返回给客户。
Socket是一种底层连接。客户机和服务器通过写入到Socket的字节流进行通信。它们必须有 共同的协议,也就是说,通过Socket相互传送信息时所用的语言必须是协定好的。
如果客户正试图连接到WWW,那么类URL及相关类(URL Connection、URL Encoder)比较适 合。相对来说,URL是对Web的高层连接,并且把Socket用作低层实现的一部分。



作者: 凉心无悔    时间: 2005-5-14 21:10     标题: [转帖]SOCKET编程的基本概念

socket简易入门手册(1)

1、介绍
  当你进入 UNIX 的神秘世界后,立刻会发现越来越多的东西难以理解。对于大多数人来说,BSD socket 的概念就是其中一个。这是一个很短的教程来解释他们是什么、他们如何工作并给出一些简单的代码来解释如何使用他们。
2、类比 (什么是 socket ?)
  socket 是进行程序间通讯(IPC)的 BSD 方法。这意味着 socket 用来让一个进程和其他的进程互通信息,就象我们用电话来和其他的人交流一样。
  用电话来比喻是很恰当的,我们在后面将一直用电话这个概念来描叙 socket 。
3、装上你的新电话(怎样侦听?)
  一个人要能够收到别人打给他的电话,首先他要装上一门电话。同样,你必须先建立 socket 以侦听线路。这个过程包含几个步骤。首先,你要建立一个新的 socket,就象先装上电话一样。socket() 命令就完成这个工作。
  因为 sockets 有几种类型,你要注明你要建立什么类型的。你要做一个选择是 socket 的地址格式。如同电话有音频和脉冲两种形式一样,socket 有两个最重要的选项是 AF_UNIX 和 IAF_INET。AF_UNIX 就象 UNIX 路径名一样识别 sockets。这种形式对于在同一台机器上的 IPC 很有用。而 AF_INET 使用象 192.9.200.10 这样被点号隔开的四个十进制数字的地址格式。除了机器地址以外,还可以利用端口号来允许每台机器上的多个 AF_INET socket。我们这里将着重于 AF_INET 方式,因为他很有用并广泛使用。
  另外一个你必须提供的参数是 socket 的类型。两个重要的类型是 SOCK_STREAM 和 SOCK_DGRAM。 SOCK_STREAM 表明数据象字符流一样通过 socket 。而 SOCK_DGRAM 则表明数据将是数据报(datagrams)的形式。我们将讲解 SOCK_STREAM sockets,他很常见并易于使用。
  在建立 socket 后,我们就要提供 socket 侦听的地址了。就象你还要个电话号码来接电话一样。bind() 函数来处理这件事情。
  SOCK_STREAM sockets 让连接请求形成一个队列。如果你忙于处理一个连接,别的连接请求将一直等待到该连接处理完毕。listen() 函数用来设置最大不被拒绝的请求数(一般为5个)。一般最好不要使用 listen() 函数。
  下面的代码说明如何利用 socket()、 bind() 和 listen() 函数建立连接并可以接受数据。
  /* code to establish a socket; originally from bzs@bu-cs.bu.edu
   */
int establish(unsigned short portnum)
  { char myname[MAXHOSTNAME+1];
   int s;
   struct sockaddr_in sa;
   struct hostent *hp;
memset(&sa, 0, sizeof(struct sockaddr_in)); /* clear our address */
   gethostname(myname, MAXHOSTNAME); /* who are we? */
   hp= gethostbyname(myname)

作者: 凉心无悔    时间: 2005-5-14 21:11     标题: [转帖]SOCKET编程的基本概念

(2)
; /* get our address info */
   if (hp == NULL) /* we dont exist !? */
   return(-1);
   sa.sin_family= hp->h_addrtype; /* this is our host address */
   sa.sin_port= htons(portnum); /* this is our port number */
   if ((s= socket(AF_INET, SOCK_STREAM, 0)) /* obligatory includes */
  #include
  #include
  #include
  #include
  #include
  #include
  #include
  #include
#define PORTNUM 50000 /* random port number, we need something */
void fireman(void);
  void do_something(int);
main()
  { int s, t;
if ((s= establish(PORTNUM)) 0)
   ;
  }
/* this is the function that plays with the socket. it will be called
   * after getting a connection.
   */
  void do_something(int s)
  {
   /* do your thing with the socket here
   :
   :
   */
  }
  4、拨号 (如何调用 socket)
  现在你应该知道如何建立 socket 来接受调用了。那么如何调用呢?和电话一样,你要先有个电话。用 socket() 函数来完成这件事情,就象建立侦听的 socket 一样。
  在给 socket 地址后,你可以用 connect() 函数来连接侦听的 socket 了。下面是一段代码。
  int call_socket(char *hostname, unsigned short portnum)
  { struct sockaddr_in sa;
   struct hostent *hp;
   int a, s;
if ((hp= gethostbyname(hostname)) == NULL) { /* do we know the hosts */
   errno= ECONNREFUSED; /* address? */
   return(-1); /* no */
   }
memset(&sa,0,siz

作者: 凉心无悔    时间: 2005-5-14 21:11     标题: [转帖]SOCKET编程的基本概念

(3)
eof(sa));
   memcpy((char *)&sa.sin_addr,hp->h_addr,hp->h_length); /* set address */
   sa.sin_family= hp->h_addrtype;
   sa.sin_port= htons((u_short)portnum);
if ((s= socket(hp->h_addrtype,SOCK_STREAM,0)) 0) {
   bcount += br; /* increment byte counter */
   buf += br; /* move buffer ptr for next read */
   }
   else if (br < 0) /* signal an error to the caller */
   return(-1);
   }
   return(bcount);
  }
  相同的函数也可以写数据,留给我们的读者吧。
  5、谈话
  6、挂起(结束)
  和你通过电话和某人交谈后一样,你要在 socket 间关闭连接。一般 close() 函数用来关闭每边的 socket 连接。如果一边的已经关闭,而另外一边却在向他写数据,则返回一个错误代码。
  7、世界语(交流的语言很重要)
  现在你可以在机器间联络了,可是要小心你所说的话。许多机器有自己的方言,如 ASCII 和 EBCDIC。更常见的问题是字节顺序问题。除非你一直传输的都是文本,否则你一定要注意这个问题。幸运的是,人们找出了解决的办法。
  在很久以前,人们争论哪种顺序更“正确”。现在必要时有相应的函数来转换。其中有 htons()、ntohs()、htonl() 和 ntohl()。在传输一个整型数据前,先转换一下。
  i= htonl(i);
  write_data(s, &i, sizeof(i));
  在读数据后,再变回来。
  read_data(s, &i, sizeof(i));
  i= ntohl(i);
  如果你一直坚持这个习惯,你将比别人少出错的机会。
  8、未来在你的掌握了(下一步?)
  就用我们刚才讨论的东西,你就可以写自己的通讯程序了。和对待所有的新生事物一样, 最好还是看看别人已经做了些什么。这里有许多关于 BSD socket 的东西可以参考。
  请注意,例子中没有错误检查,这在“真实”的程序中是很重要的。你应该对此充分重视。





欢迎光临 黑色海岸线论坛 (http://bbs.thysea.com/) Powered by Discuz! 7.2