BSD Socket编程快速入门(一)
这是一篇简易的socket编程入门文章,可以让您快速建立起socket编程的概念。本文翻译自BSD Sockets: A Quick And Dirty Primer(http://www.frostbytes.com/~jimf/papers/sockets/sockets.html),如需转载本译本请务必注明原英文版出处,如果您愿意也请您请注明翻译译本来自学与思编程网,谢谢!
BSD Sockets: A Quick And Dirty Primer
Jim Frost(http://www.frostbytes.com/~jimf)
Software Tool & Die
Copyright (c) 1988, 1994 Jim Frost
All Rights Reserved
Last changed December 8, 1996
序言
当您初入神秘的unix世界时,您会发现越来越多的事情不是一下就能搞明白的,其中之一就是BSD socket的概念。本文是一个极其简易的入门文章,旨在帮助您了解BSD socket的概念,理解其工作原理,我也会向大家展示一些代码来帮助您更好的掌握怎么使用它。
什么是socket
socket是进程间通信的方法,这就意味着我们可以用它来实现进程间的通信,这就跟我们平时使用电话来跟亲朋好友聊天一样,电话两头的人就像两个进程一样,电话就类似于socket。
怎么才能接听到电话(或则怎么监听socket连接请求)
为了能接听电话,您要做的第一件事情就是安装一部电话。进程间通信也一样,为了跟其它进程通信,首先就要创建一个socket来等待别人的连接请求。怎么创建socket呢,很简单,用socket()这个系统调用(函数)就行了。
因为socket可以有多种类型,所以在创建socket时,一定要给socket()函数指明您想创建的socket的类型。这里所说的类型其实是由多个选项组合而成的,也就是多个选项组合在一起确定一个socket类型。选项之一就是地址格式。就像我们日常生活中的通信一样,可以选择用电话号码为地址的电话通信,也可以选择用某某街道多少号这种传统的信件通信,socket也一样,需要你指定socket的地址格式,指定了地址格式就相当于你选择了用哪种通信方式来通信。最常见的socket地址格式有AF_UNIX和AF_INET。AF_UNIX这种格式是一个包含绝对路径的文件名,它只能用于同一台电脑上的进程间通信;AF_INET地址格式是(IP:Port)地址对,它可以用于不同电脑上的进程间通信,IP的格式是4字节表示的一个数,但我们平时为了好记,都用4个点隔的十进制数表示(比如192.168.0.1,一个字节对应一个十进制数并用点(.)分开),port用来区分不同的进程,如果这里不好理解您可以想象一下电话分机,同一个电话号码(相当于IP)可能还有多个分机(相当于port)。本文主要讲述AF_INET这种socket,因为使用得更广泛。
另一个构成socket类型的选项是通信类型。最常用的两种类型就是SOCK_STREAM和SOCK_DGRAM。SOCK_STREAM数据是通过字节流来往于不同的进程之间, 而SOCK_DGRAM数据是通过一块一块(称之为数据报)来往于不同进程之间的。本文只描述SOCK_STREAM这种类型, 因为它最简单也最常用。
跟你安装好电话后还得有一个电话号码一样,创建好socket后,您还要给socket提供一个监听地址。bind()函数就可以用来给一个socket指定一个监听地址。
SOCK_STREAM类型的socket有能力对连接请求排队,就像你的电话可以“呼叫等待”一样。如果您正忙于处理一个连接,那么排队中的请求就会一直等到您处理完该连接。listen()可以让您指定最多可以有多少未处理连接处于等待状态。
下面的代码向您展示如何使用上面提到socket(), bind()和listen()这些函数来建立一个可以监听连接请求的socket:
/* 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); /* get our address info */
if (hp == NULL) /* we don’t 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)) < 0) /* create socket */
return(-1);
if (bind(s,(struct sockaddr *)&sa,sizeof(struct sockaddr_in)) < 0) { /* bind address to socket */
close(s);
return(-1);
}
listen(s, 3); /* max # of queued connects */
return(s);
}
当您创建好可以监听连接请求的socket后,您需要用accept()函数来等待连接请求,当有新的连接请求到来后,accept()返回一个新的已经建立好连接的socket,利用这个socket我们就可以收发数据了。下面的代码可以用来接受连接请求:
/* wait for a connection to occur on a socket created with establish() */
int get_connection(int s)
{
int t; /* socket of connection */
if ((t = accept(s,NULL,NULL)) < 0) /* accept connection if there is one */
return(-1);
return(t);
}
——————未完待续——————–
