关于socket编程

使用socket之前要先通过WSAStartup()函数加载socket库和进行该库的版本协商,注意其第一个参数wVersionRequested 通过MAKEWORD宏来获取,宏参数的高位字节代表该库副版本,而高位字节代表主版本。对于每一个WSAStartup()的成功调用(成功加载WinSock.dll后),在最后都对应于一个WSACleanUp调用,以释放为该应用进程释放的资源。

1、基于TCP(面向连接)的socket编程
      服务器端程序:
1)、创建套接字(socket)。    SOCKET sockSrv = socket(AF_INIT, SOCK_STREAM, 0),第一个参数指定地址族,对于TCP/IP协议的套接字,它只能是AF_INIT(也可以写成PF_INIT),第二个参数指定套接字类型,第三个参数是与特定地址家族相关的协议,一般指定为0,自动根据前两个参数选择协议。
2)、将套接字绑定到一个本地地址和端口上(bind)。bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));第一个参数指定要绑定的套接字,第二个参数该套接字的本地地址信息(见补充1),第三个参数指定该地址结构的长度。
3)、将套接字设为监听模式,准备接收客户请求(listen)。listen(sockSrv, 5);第二个参数是等待连接队列的最大长度。
4)、等待客户请求到来;当请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept)。SOCKET sockConn = accept(sockSrv, (SOCKADDR*)&addrClient, &len);保存了客户端的地址结构,只是返回的客户端地址结构的长度。返回一个新建连接的套接字,通过该套接字和客户端通讯。
5)、用返回的套接字和客户端进行通信(send/recv)。
6)、返回,等待另一客户请求。
7)、关闭套接字。closesocket(sockConn);
WSACleanup();终止对套接字库的使用。

客户端程序:
1)、创建套接字(socket)。    SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);
2)、向服务器发出连接请求(connect)。connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));第二个参数为需要连接的服务器端的地址信息。
3)、和服务器端进行通信(send/recv)。
4)、关闭套接字。closesocket(sockClient);
 
2、基于UDP(面向无连接)的socket编程
服务器端(接收端)程序:
1)、创建套接字(socket)。    
2)、将套接字绑定到一个本地地址和端口上(bind)。
3)、等待接收数据(recvfrom)。
4)、关闭套接字。

客户端(发送端)程序:
1)、创建套接字(socket)。    
2)、向服务器发送数据(sendto)。
3)、关闭套接字。

补充:
1)、sockaddr结构定义如下:
    struct sockaddr {
      u_short sa_family;
      char sa_data[14];
     };
sockaddr的第一个字段sa_family指定该地址家族,在这里必须设为AF_INET。sa_data仅仅是表示要求一块内存分配区,起到占位的作用,该区域中指定与协议相关的具体地址信息。由于实际要求的只是内存区,所以对于不同的协议家族,用不同的结构来替换sockaddr。除了sa_family外,sockaddr是按网络字节顺序表示的。在TCP/IP中,我们可以用sockaddr_in结构替换sockaddr,以方便我们填写地址信息。
sockaddr_in的定义如下:
  struct sockaddr_in{
  short sin_family;
  unsigned short sin_port;
  struct   in_addr sin_addr;
  char sin_zero[8];
};
其中n_addr的结构定义:
struct in_addr {
union {
struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { u_short s_w1,s_w2; } S_un_w;
u_long S_addr;
} S_un;
};

                  其中,sin_family表示地址族,对于IP地址,sin_family成员将一直是AF_INET。成员sin_port指定的是将要分配给套接字的端口。成员sin_addr给出的是套接字的主机IP地址。而成员sin_zero只是一个填充数,以使sockaddr_in结构和sockaddr结构的长度一样。如果这个函数调用成功,它将返回0。如果调用失败,这个函数就会返回一个SOCKET_ERROR,错误信息可以通过WSAGetLastError函数返回。将IP地址指定为INADDR_ANY,允许套接字向任何分配给本地机器的IP地址发送或接收数据。多数情况下,每个机器只有一个IP地址,但有的机器可能会有多个网卡,每个网卡都可以有自己的IP地址,用INADDR_ANY可以简化应用程序的编写。将地址指定为INADDR_ANY,允许一个独立应用接受发自多个接口的回应。如果我们只想让套接字使用多个IP中的一个地址,就必须指定实际地址,要做到这一点,可以用inet_addr()函数,这个函数需要一个字符串作为其参数,该字符串指定了以点分十进制格式表示的IP地址(如192.168.0.16)。而且inet_addr()函数会返回一个适合分配给S_addr的u_long类型的数值。inet_ntoa()函数会完成相反的转换,它接受一个in_addr结构体类型的参数并返回一个以点分十进制格式表示的IP地址字符串。注意我们sockaddr地址结构体中的成员,除了sin_family之外,其他的成员都要使用网络字节序(高地址先存,低地址后存,而一般的基于inter的CPU都是低地址现存,高地址后存),所以我们要把这些成员改变为网络字节序(htonl(INADDR_ANY);相关的操作)

2)、需要包含头文件Winsock2.h和链接Ws2_32.lib库。

你可能感兴趣的:(编程,socket,struct,Stream,网络,服务器)