Berkeley sockets

http://www.google.com/gwt/n?u=http%3A%2F%2Fen.wikipedia.org%2Fwiki%2FBerkeley_sockets&_gwt_pg=0

http://blog.csdn.net/hust_wh/archive/2004/08/25/83970.aspx

 

套接字的一些基本知识
好的,从现在开始,我们应该谈些和程序有关的事情了。
6.5.1 基本结构
首先,我想介绍一些使用套接字编程中常见的网络数据结构对大家会很有帮助。
1.struct sockaddr
这个结构用来存储套接字地址。
数据定义:
struct sockaddr {
unsigned short sa_family; /* address族, AF_xxx */
char sa_data[14]; /* 14 bytes的协议地址*/
};
sa_family 一般来说,都是“AFINET”。
sa_data 包含了一些远程电脑的地址、端口和套接字的数目,它里面的数据是杂溶在一
切的。
为了处理struct sockaddr, 程序员建立了另外一个相似的结构struct sockaddr_in:
struct sockaddr_in (“in” 代表“Internet”)
struct sockaddr_in {
short int sin_family; /* Internet地址族*/
unsigned short int sin_port; /* 端口号*/
struct in_addr sin_addr; /* Internet地址*/
unsigned char sin_zero[8]; /* 添0(和struct sockaddr一样大小)*/
};
这个结构提供了方便的手段来访问socket address(struct sockaddr)结构中的每一个元
素。注意sin_zero[8] 是为了是两个结构在内存中具有相同的尺寸,使用sockaddr_in 的时
候要把sin_zero 全部设成零值(使用bzero()或memset()函数)。而且,有一点很重要,就
是一个指向struct sockaddr_in 的指针可以声明指向一个sturct sockaddr 的结构。所以虽然
socket() 函数需要一个structaddr * ,你也可以给他一个sockaddr_in * 。注意在struct
sockaddr_in 中,sin_family 相当于在struct sockaddr 中的sa_family,需要设成“AF_INET”。
最后一定要保证sin_port 和sin_addr 必须是网络字节顺序(见下节)!
2.struct in_addr
其定义如下:
/* 因特网地址(a structure for historical reasons) */
第6 章berkeley 套接字- 145 -
struct in_addr {
unsigned long s_addr;
};
如果你声明了一个“ ina ” 作为一个struct sockaddr_in 的结构, 那么
“ina.sin_addr.s_addr”就是4 个字节的IP 地址(按网络字节顺序排放)。需要注意的是,
即使你的系统仍然使用联合而不是结构来表示struct in_addr,你仍然可以用上面的方法得
到4 个字节的IP 地址(一些#defines 帮了你的忙)。
6.5.2 基本转换函数
在前面提到了网络字节顺序。那么什么是网络字节顺序,它有什么特殊性,又如何将
我们通常使用的数据转换成这种格式呢?
1.网络字节顺序
因为每一个机器内部对变量的字节存储顺序不同(有的系统是高位在前,底位在后,
而有的系统是底位在前,高位在后),而网络传输的数据大家是一定要统一顺序的。所以
对与内部字节表示顺序和网络字节顺序不同的机器,就一定要对数据进行转换(比如IP 地
址的表示,端口号的表示)。但是内部字节顺序和网络字节顺序相同的机器该怎么办呢?
是这样的:它们也要调用转换函数,但是真正转换还是不转换是由系统函数自己来决定的。
2.有关的转化函数
我们通常使用的有两种数据类型:短型(两个字节)和长型(四个字节)。下面介绍
的这些转换函数对于这两类的无符号整型变量都可以进行正确的转换。
如果你想将一个短型数据从主机字节顺序转换到网络字节顺序的话,有这样一个函
数:它是以“h”开头的(代表“主机”);紧跟着它的是“to”,代表“转换到”;然后是“n”
代表“网络”;最后是“s”,代表“短型数据”。H-to-n-s,就是htons() 函数(可以使用Host
to Network Short 来助记)
很简单吧??我没有理解的时候觉得这个函数不好记呢??
你可以使用“n”,“h”,“to”,“s”,“l”的任意组合??当然,你要在可能的情况下
进行组合。比如,系统是没有stolh() 函数的(Short to Long Host?)。
下面给出套接字字节转换程序的列表:
l htons()——“Host to Network Short” 主机字节顺序转换为网络字节顺序(对无符号
短型进行操作4 bytes)
l htonl()——“Host to Network Long” 主机字节顺序转换为网络字节顺序(对无符
号长型进行操作8 bytes)
l ntohs()——“Network to Host Short “ 网络字节顺序转换为主机字节顺序(对无符
号短型进行操作4 bytes)
l ntohl()——“Network to Host Long “ 网络字节顺序转换为主机字节顺序(对无符
号长型进行操作8 bytes)
注意:现在你可能认为自己已经精通于这几个函数的用处了??你可能会想:“恩??在我的68000
机器内部,字节的表示顺序已经是网络字节顺序了,那么我的程序里就不必调用htonl() 来转换我的IP 地
址了”。是的,你可能是对的。但是假如你把你的程序移植到一个内部字节顺序和网络字节顺序相反的机
器上,你的程序就会运行不正常!所以,一定要记住:在你把数据发送到Internet 之前,一定要把它的字

 /* Server code in C */

#include <sys/types.h>
#include <sys/socket.h>
  #include <netinet/in.h>
  #include <arpa/inet.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <unistd.h>

  int main(void)
  {
    struct sockaddr_in stSockAddr;
    int i32SocketFD = socket(PF_INET, SOCK_STREAM, 0);

    if(-1 == i32SocketFD)
    {
      perror("can not create socket");
      exit(EXIT_FAILURE);
    }

    memset(&stSockAddr, 0, sizeof(stSockAddr));

    stSockAddr.sin_family = PF_INET;
    stSockAddr.sin_port = htons(1100);
    stSockAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    if(-1 == bind(i32SocketFD,(const void *)&stSockAddr, sizeof(stSockAddr)))
    {
      perror("error bind failed");
      close(i32SocketFD);
      exit(EXIT_FAILURE);
    }

    if(-1 == listen(i32SocketFD, 10))
    {
      perror("error listen failed");
      close(i32SocketFD);
      exit(EXIT_FAILURE);
    }

    for(;;)
    {
      int i32ConnectFD = accept(i32SocketFD, NULL, NULL);

      if(0 > i32ConnectFD)
      {
        perror("error accept failed");
        close(i32ConnectFD);
        close(i32SocketFD);
        exit(EXIT_FAILURE);
      }

     /* perform read write operations ... */

      shutdown(i32ConnectFD, SHUT_RDWR);

      close(i32ConnectFD);
    }
    return 0;
  }

 

Client

Setting up a TCP client involves the following steps:

  • Creating a TCP socket, with a call to socket().
  • Connecting to the server with the use of connect(), passing a sockaddr_in structure with the sin_family set to PF_INET or PF_INET6, sin_port set to the port the endpoint is listening (in network byte order), and sin_addr set to the IPv4 or IPv6 address of the listening server (also in network byte order.)
  • Communicating with the server by using send() and recv() or write() and read().
  • Terminating the connection and cleaning up with a call to close(). Again, if there were any calls to fork(), each process must close() the socket.
  /* Client code in C */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(void)
{
struct sockaddr_in stSockAddr;
int i32Res, i32SocketFD = socket(PF_INET, SOCK_STREAM, 0);

if(-1 == i32SocketFD)
{
perror("cannot create socket");
exit(EXIT_FAILURE);
}

memset(&stSockAddr, 0, sizeof(stSockAddr));

stSockAddr.sin_family = PF_INET;
stSockAddr.sin_port = htons(1100);
i32Res = inet_pton(PF_INET, "192.168.1.3", &stSockAddr.sin_addr);

if(0 > i32Res)
{
perror("error: first parameter is not a valid address family");
close(i32SocketFD);
exit(EXIT_FAILURE);
}
else if(0 == i32Res)
{
perror("char string (second parameter does not contain valid ipaddress");
close(i32SocketFD);
close(i32Res);
exit(EXIT_FAILURE);
}

if(-1 == connect(i32SocketFD, (const void *)&stSockAddr, sizeof(stSockAddr)))
{
perror("connect failed");
close(i32SocketFD);
close(i32Res);
exit(EXIT_FAILURE);
}

/* perform read write operations ... */

shutdown(i32SocketFD, SHUT_RDWR);

close(i32SocketFD);
close(i32Res);
return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值