大家学习Linux下socket有什么好的书没

linux下socket编程实例
一、基本socket函数
Linux系统是通过提供套接字(socket)来进行网络编程的。网络的socket数据传输是一种特殊的I/O,socket也是一种文件描述符。socket也有一个类似于打
开文件的函数:socket(),调用socket(),该函数返回一个整型的socket的描述符,随后的连接建立、数据传输等操作也都是通过该socket实现。
1、socket函数
&& int socket(int domain, int
type, int protocol);
功能说明:
调用成功,返回socket文件描述符;失败,返回-1,并设置errno
参数说明:
  domain指明所使用的协议族,通常为PF_INET,表示TCP/IP协议;
  type参数指定socket的类型,基本上有三种:数据流套接字、数据报套接字、原始套接字
  protocol通常赋值"0"。
  两个网络程序之间的一个网络连接包括五种信息:通信协议、本地协议地址、本地主机端口、远端主机地址和远端协议端口。socket数据结构中包含这五种信息。
2、bind函数
&& int bind(int sock_fd,struct
sockaddr_in *my_addr, int addrlen);
功能说明:
将套接字和指定的端口相连。成功返回0,否则,返回-1,并置errno.
参数说明:
sock_fd是调用socket函数返回值,
  my_addr是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针;
  struct sockaddr_in结构类型是用来保存socket信息的:
  struct sockaddr_in {
  short int sin_
  unsigned short int sin_
  struct in_addr sin_
  unsigned char sin_zero[8];
addrlen为sockaddr的长度。
3、connect函数
connect(int sock_fd, struct sockaddr *serv_addr,int addrlen);
功能说明:
客户端发送服务请求。成功返回0,否则返回-1,并置errno。
参数说明:
&& sock_fd
是socket函数返回的socket描述符;serv_addr是包含远端主机IP地址和端口号的指针;addrlen是结构sockaddr_in的长度。
4、listen函数
&& int listen(int sock_fd, int
功能说明:
等待指定的端口的出现客户端连接。调用成功返回0,否则,返回-1,并置errno.
参数说明:
&& sock_fd 是socket()函数返回值;
&& backlog指定在请求队列中允许的最大请求数
5、accecpt函数
&& int accept(int sock_fd, struct
sockadd_in* addr, int addrlen);
功能说明:
用于接受客户端的服务请求,成功返回新的套接字描述符,失败返回-1,并置errno。
参数说明:
&& sock_fd是被监听的socket描述符,
addr通常是一个指向sockaddr_in变量的指针,
addrlen是结构sockaddr_in的长度。
6、write函数
&&& ssize_t
write(int fd,const void *buf,size_t nbytes)
功能说明:
write函数将buf中的nbytes字节内容写入文件描述符fd.成功时返回写的字节数.失败时返回-1.
并设置errno变量.
在网络程序中,当我们向套接字文件描述符写时有俩种可能:
1)write的返回值大于0,表示写了部分或者是全部的数据.
2)返回的值小于0,此时出现了错误.需要根据错误类型来处理.
如果错误为EINTR表示在写的时候出现了中断错误.
如果错误为EPIPE表示网络连接出现了问题.
7、read函数
&&& ssize_t
read(int fd,void *buf,size_t nbyte)
函数说明:
read函数是负责从fd中读取内容.当读成功时,read返回实际所读的字节数,如果返回的值是0
表示已经读到文件的结束了,小于0表示出现了错误.
如果错误为EINTR说明读是由中断引起的,
如果错误是ECONNREST表示网络连接出了问题.
8、close函数
int close(sock_fd);
当所有的数据操作结束以后,你可以调用close()函数来释放该socket,从而停止在该socket上的任何数据操作:
函数运行成功返回0,否则返回-1
二、socket编程的其他函数说明
1、 网络字节顺序及其转换函数
1) 网络字节顺序
每一台机器内部对变量的字节存储顺序不同,而网络传输的数据是一定要统一顺序的。所以对内部字节表示顺序与网络字节顺序不同的机器,
一定要对数据进行转换,从程序的可移植性要求来讲,就算本机的内部字节表示顺序与网络字节顺序相同也应该在传输数据以前先调用数据转换函数,
以便程序移植到其它机器上后能正确执行。真正转换还是不转换是由系统函数自己来决定的。
2) 有关的转换函数
* unsigned short int htons(unsigned short int hostshort):
主机字节顺序转换成网络字节顺序,对无符号短型进行操作4bytes
* unsigned long int htonl(unsigned long int hostlong):
主机字节顺序转换成网络字节顺序,对无符号长型进行操作8bytes
* unsigned short int ntohs(unsigned short int netshort):
网络字节顺序转换成主机字节顺序,对无符号短型进行操作4bytes
* unsigned long int ntohl(unsigned long int netlong):
网络字节顺序转换成主机字节顺序,对无符号长型进行操作8bytes
注:以上函数原型定义在netinet/in.h里
2、IP地址转换
有三个函数将数字点形式表示的字符串IP地址与32位网络字节顺序的二进制形式的IP地址进行转换
(1) unsigned long int inet_addr(const char *
cp):该函数把一个用数字和点表示的IP地址的字符串转换成一个无符号长整型,如:struct sockaddr_in
ina.sin_addr.s_addr=inet_addr("202.206.17.101")
该函数成功时:返回转换结果;失败时返回常量INADDR_NONE,该常量=-1,二进制的无符号整数-1相当于255.255.255.255,这是一个广播地址,所以在程序中调用iner_addr()时,一定要人为地对调用失败进行处理。由于该函数不能处理广播地址,所以在程序中应该使用函数inet_aton()。
(2)int inet_aton(const char * cp,struct in_addr *
inp):此函数将字符串形式的IP地址转换成二进制形式的IP地址;成功时返回1,否则返回0,转换后的IP地址存储在参数inp中。
(3) char * inet_ntoa(struct in-addr
in):将32位二进制形式的IP地址转换为数字点形式的IP地址,结果在函数返回值中返回,返回的是一个指向字符串的指针。
3、字节处理函数
Socket地址是多字节数据,不是以空字符结尾的,这和C语言中的字符串是不同的。Linux提供了两组函数来处理多字节数据,一组以b(byte)开头,是和BSD系统兼容的函数,另一组以mem(内存)开头,是ANSI
C提供的函数。
以b开头的函数有:
(1) void bzero(void * s,int
n):将参数s指定的内存的前n个字节设置为0,通常它用来将套接字地址清0。
(2) void bcopy(const void * src,void * dest,int
n):从参数src指定的内存区域拷贝指定数目的字节内容到参数dest指定的内存区域。
(3) int bcmp(const void * s1,const void * s2,int
n):比较参数s1指定的内存区域和参数s2指定的内存区域的前n个字节内容,如果相同则返回0,否则返回非0。
注:以上函数的原型定义在strings.h中。
以mem开头的函数有:
(1) void * memset(void * s,int c,size_t
n):将参数s指定的内存区域的前n个字节设置为参数c的内容。
(2) void * memcpy(void * dest,const void * src,size_t
n):功能同bcopy(),区别:函数bcopy()能处理参数src和参数dest所指定的区域有重叠的情况,memcpy()则不能。
(4) int memcmp(const void * s1,const void * s2,size_t
n):比较参数s1和参数s2指定区域的前n个字节内容,如果相同则返回0,否则返回非0。
注:以上函数的原型定义在string.h中。
二、程序说明
本使用tcp协议进行通信,服务端进行监听,在收到客户端的连接后,发送数据给客户端;客户端在接受到数据后打印出来,然后关闭。
1、client.c
#include &stdlib.h&
#include &sys/types.h&
#include &stdio.h&
#include &sys/socket.h&
#include &netinet/in.h&
#include &string.h&
int main()
buffer[1024]={0};&&&
struct sockaddr_in s_add,c_
unsigned short portnum=0x8888;&
printf("Hello,welcome to client !\r\n");
cfd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == cfd)
printf("socket fail ! \r\n");
&&& return
printf("socket ok !\r\n");
bzero(&s_add,sizeof(struct sockaddr_in));
s_add.sin_family=AF_INET;
s_add.sin_addr.s_addr= inet_addr("192.168.1.2");
s_add.sin_port=htons(portnum);
printf("s_addr = %#x ,port :
%#x\r\n",s_add.sin_addr.s_addr,s_add.sin_port);
if(-1 == connect(cfd,(struct sockaddr *)(&s_add),
sizeof(struct sockaddr)))
printf("connect fail !\r\n");
&&& return
printf("connect ok !\r\n");
if(-1 == (recbytes = read(cfd,buffer,1024)))
&&& printf("read
data fail !\r\n");
&&& return
printf("read ok\r\nREC:\r\n");
buffer[recbytes]='\0';
printf("%s\r\n",buffer);
getchar();
close(cfd);
2、server.c
#include &stdlib.h&
#include &sys/types.h&
#include &stdio.h&
#include &sys/socket.h&
#include &netinet/in.h&
#include &string.h&
int main()
struct sockaddr_in s_add,c_
unsigned short portnum=0x8888;
printf("Hello,welcome to my server !\r\n");
sfp = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == sfp)
printf("socket fail ! \r\n");
&&& return
printf("socket ok !\r\n");
bzero(&s_add,sizeof(struct sockaddr_in));
s_add.sin_family=AF_INET;
s_add.sin_addr.s_addr=htonl(INADDR_ANY);
s_add.sin_port=htons(portnum);
if(-1 == bind(sfp,(struct sockaddr *)(&s_add),
sizeof(struct sockaddr)))
&&& printf("bind
fail !\r\n");
&&& return
printf("bind ok !\r\n");
if(-1 == listen(sfp,5))
printf("listen fail !\r\n");
&&& return
printf("listen ok\r\n");
sin_size = sizeof(struct sockaddr_in);
nfp = accept(sfp, (struct sockaddr *)(&c_add),
&sin_size);
if(-1 == nfp)
printf("accept fail !\r\n");
&&& return
printf("accept ok!\r\nServer start get connect from %#x :
%#x\r\n",ntohl(c_add.sin_addr.s_addr),ntohs(c_add.sin_port));
if(-1 == write(nfp,"hello,welcome to my server \r\n",32))
printf("write fail!\r\n");
&&& return
printf("write ok!\r\n");
close(nfp);
close(sfp);
在cygwin下,使用gcc命令编译如下:
gcc -o server server.c
gcc -o client client.c
然后运行程序:
server执行效果如下:
Hello,welcome to my server !
socket ok !
accept ok!
Server start get connect from 0xc0a80102 : 0xc927
client执行效果如下:
Hello,welcome to client !
socket ok !
s_addr = 0x201a8c0 ,port : 0x8888
connect ok !
hello,welcome to my server
本文欢迎转载,转载请注明出处和作者
作者:流星
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。Linux Socket学习
您当前位置: &&
&& Linux Socket学习
Linux Socket学习
07:53:51 来源:中国IT部落 浏览:1次
  在另一个方式上,套接口也与电话类似。当我们要打给某人,我们拨打我们要联系的人的电话号码。套接口有网络地址而不是电话号码。通过指定远程套接口地址,我们的程序可以在我们的本地套接口与远程端点之间建立一条通信线。
  这就意味着,我们作为一个程序员,可以将套接口当作打开的文件一样来使用。通过文件单元数交互的来引用文件和套接口的能力提供给了我们极大的灵活性。这就意味着read和write函数可以同时在打开的文件和套接口上进行操作。
  这些应是我们已经熟悉的Linux的输入/输入函数。通过回顾我们可以看到,read函数返从文件描述符fd中返回最大count字节的输入,存放到buf缓冲区中。返回值代表实际读取的字节数。如果返回0则代表文件结束。
  write函数将我们指定的buf缓冲区中总计count的字节写入文件描述符fd中。返回值代表实际写入的字节数。通常这必须与指定的count参数相匹配。然而也会有一些情况,这个值要count小,但是我们没有必要担心这样的情况。
  在前面,我们看到如何来创建一对套接口,并且看到如何使用这些套接口来执行最基本的输入与输出操作。我们也可以看到套接口可以使用与通过调用close函数来关闭文件的方式来关闭。现在我们来了解一下关闭套接口所提供的函数。
  当本地进程希望通知远程端不再接收数据时就会出现问题。如果本地进程关闭了他的套接口,这是可以适用的。然而,如果他希望从远程端接收一个确认信息,这是不可能的,因为现在他的套接口已经关闭了。这样的情况需要一个半关闭套接口的方法。
  在这个例子中,第一个close函数调用不会有任何效果。先关闭其中的任何一个都是一样的结果。关闭s或者d将会为同一个套接口保留一个文件描述符。只有通过close函数调用来关闭最后一个存在的文件描述符才会有效果。在这个例子中,关闭d文件描述符关闭了这个套接口。
  现在我们要来解释一下domain参数。对于socketpair函数,这个值必须为AF_LOCAL或者AF_UNIX。在上一章,我们已经指出AF_UNIX宏与旧版的AF_LOCAL等同。然而AF_LOCAL意味着什么?他选择了什么呢?
  通用套接口地址结构对于程序而言并不是那样有用。然而,他确实提供了其他地址结构必须适合的引用模型。例如,我们将会了解到所有地址必须在结构中的同样的定义一个sa_mily,因为这个元素决定了地址结构的剩余字节数。
  这个地址结构用在我们的本地套接口中(我们的运行Linux的PC)。例如,当我们使用lpr命令排除要打印的文件时,他使用一个本地套接口与我们的PC上假脱机服务器进行通信。虽然也可以用TCP/IP协议来进行本地通信,但是事明这是低效的。
  linuxsocket学习传统本地地址的地址名空间为文件系统径名。一个进程也许会用任何可用的径名来命名他的本地套接口。然则为了可用,命名套接口的进程必须可以访问径名的所有目录组件,并且有权限来在指定的目录中创建最终的套接口对象。
  下面的例子演示了一个简单的初始化sockaddr_un结构的C程序,然后调用netstat命令来证明他起到了作用。在这里我们要先记住在socket与bind上的程序调用,这是两个我们还没有涉及到的函数。
  Linux2.2内核使得为本地套接口创建一个抽象名了成为可能。他的方法就是使得径名的第一个字节为一个空字节。在径名中空字节之后的字节才会成为抽象名字的一部分。下面的这个程序是上一个例子程序的修改版本。这个程序采用了一些不同的方法来创建一个抽象的名字。
  从这个输出结果中我们可以看到,套接口地址是以@MYSOCKET的名字出现的。开头的@标志是为netstat命令用来标识抽象UNIX套接口名字。其余的字符是拷贝到字符数组剩余的字符。注意@字符出现在我们的Z字符应出现的地方。
  4在第49行使用strncpy函数将抽象名字拷贝到adr_unix.sun_path中。在这里要注意,为了SUN_LEN()宏的使用在目的字符数组的放置了一个结束的空字节。否则就不需要这个结束的空字节。
  在Linux下使用最多的地址族为AF_INET。这为一个套接口指定一个IPv4套接口地址,从而使得这个套接口可以通过TCP/IP网络与其他的主机进行通信。定义了sockaddr_in结构的包含头文件是由下面的C语句来进行定义的:
  上个图所演示的为十进制的数4660,以十六进制表示则为0x1234.这个数值需要用两个字节来表示。从这个图我们可以看到或者我们可以首先放置最重的字节(大端),或者是我们可以首先放置最不重要的字节(小端)。这种选择常模糊的,而这最终涉及到CPU的设计。
  我们也许已经知道,IntelCPU使用小端字节顺序。其他的CPU,例如Motorola68000系列使用大端字节顺序。在这里我们要考虑的最重要的事情就是这两种类型的CPU都存在,而且他们要连接到同一个网络。
  在这里我们可以看出网络地址一个确定的长度。如果我们回顾一下上一个例子,我们就可以很容易的看出来。然而,我们要记得AF_LOCAL的地址长度是变化的。对于AF_INET的地址,我们只需简单的提供sockaddr_in结构的大小。在C语言中为:
  套接口接口允许程序员使用在Linux下可用的其他的协议。我们要处理的代码之间的一个主要区别就是套接口是如何编址的。我们已经知道如何初始化一个AF_INET或是AF_LOCAL地址。X.25地址的创建也是类似的。
上一篇:没有了
15:39:40 07:53:51 07:53:51 07:34:08 07:33:59 07:33:50 07:33:40 07:33:31
共有0人对本文发表评论(网友评论仅供表达个人看法,并不表明本站同意其观点或证实其描述)
06-1406-1406-1406-1406-1206-1206-1206-1206-1206-12
赞助商链接
09-0607-1207-1507-0807-1207-1207-1207-1207-1207-12}

我要回帖

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信