第1章 网络编程基础(2)——Socket编程原理

Socket编程原理

Socket是网络通信端点的一种抽象,它提供了一种发送和接收数据的机制。

  • 流socket(SOCK_STREAM):双向、有序、无重复、并且无记录边界
  • 数据报Socket(SOCK_DGRAM):双向、保留记录边界

 面向连接的操作比无连接的操作效率低,但数据的安全性更高。

Socket通信流程

IP地址标志主机,端口号标志进程,IP加上端口号才能确定连接目标。

 

一个网络连接需要以下5种信息:

  1. 本地协议端口:指出接收报文或数据的进程。
  2. 本地主机地址:指出接收数据包的主机。
  3. 远程协议端口:指出目的进程或成。
  4. 远程主机地址:指出目的主机。
  5. 协议:指出程序在网络上传输数据时使用的协议。

Socket函数(Winsock)

1.Socket:用于创建一个Socket套接字。

SOCKET Socket(
int af,          //使用的协议族    
int type,        //Socket类型
int protocol     //使用的协议地址
);

Socket协议族在计算机里表示为一个整数,可以取值AF_INET

Socket类型有两种:SOCK_STREAM和SOCK_DGRAM代表流Socket和数据报Socket

函数如果成功,返回一个Socket描述字,否则,返回INVALID_SOCKET。

SOCKET s = socket(AF_INET,SOCK_STREAM,0);

2.Connect:用于尝试与远端建立一个Socket连接。

int Connect(
SOCKET s,                          //socket描述符    
const struct sockaddr* name,    //远端的地址
int namelen                        //远端地址的长度
);        

远端地址是一个SOCKADDR的结构

struct sockaddr_in(
short sin_family,                                 //socket族
u_short sin_port,                                 //端口
struct in_addr sin_addr,                          //IP地址
char sin_zero[8]                                  //结构长度
);                                    

函数如果连接成功,返回0,否则返回SOCKET_ERROR.对于非阻塞模式的Socket连接,返回结果通常是SOCKET_ERROR,并且错误代码为WSAEWOULDBLOCK,表示连接正在进行,而不是一个真正的错误。

建立连接通常是客户端发出连接请求:

SOCKET s;
SOCKADDR_IN ServerAddr;
ServerAddr.sin_family=AF_INET;
ServerAddr.sin_port=htons(Port);
ServerAddr.sin_addr.s_addr=inte_addr("127.0.0.1");
connect(s,(SOCKADDR*)&ServerAddr,sizeof(ServerAddr));

3.Send:用于在某个Socket上向远端发送数据

int send(
SOCKET s,         //Socket套接字    
const char* buf,     //存放发送数据的缓冲区
int len,          //将要发送的数据长度
int flags         //发送时使用的附加参数
);

如果发送成功,返回值为成功发送的字节数,否则返回SOCKET_ERROR。

4.Recv:与发送数据相对应的就是接收数据,函数Recv用于接收端发送的数据,函数原型为:

int recv(
SOCKET s,      //Socket套接字
char* buf,     //存放接收数据的缓冲区    
int len,       //将要接收的数据长度
int flags      //接收时使用的附加参数
);

 

接收数据成功,函数返回接收的字节数,否则,返回SOCKET_ERROR。

5.Closesocket:用于关闭不再需要的Socket

int closesocket(
SOCKET s;        //socket套接字   
);

关闭成功,返回0,否则返回SOCKET_ERROR。

6.Listen:用于在某个Socket上建立监听

int listen(
SOCKET s,      //Socket套接字
int backlog    //缓存队列的长度
);

如果建立监听成功,返回0;否则返回SOCKET_REEOR

backlog参数。设为SOMAXCONN,表示取系统连接的最大值。

7.Accept:用于接收一条新的连接。

SOCKET accept(

SOCKET s,//监听中的Socket

struct sockaddr* addr ,//表示地址结构体的指针

int* addrlen//地址结构体的长度

);

函数执行成功,返回0;否则,返回SOCKET_ERROR.

8.Bind:用于给一个Socket套接字分配一个本地协议地址

int bind(

SOCKET s,//Socket套接字

const struct socketaddr* name,//表示地址结构体的指针

int namelen//地址结构体的长度

);

 

函数执行成功,返回0;否则,返回SOCKET_ERROR.

9.Select:用于检测Socket状态,主要用于高级的网络通信模型

int select(

int nfds,//winsocj中此参数无意义

fd_set* readfds,//进行可读检测的Socket

fd_set* writefds,//进行可写检测的Socket

fd_set* exceptfds,//进行异常检测的Socket

const struct timeval* timeout//非阻塞模式中设置最大等待时间

);

 

函数执行成功,返回0;否则,返回SOCKET_ERROR.

IP地址转换

  • 无符号整数:127.0.0.1
  • ASCII地址:"127.0.0.1"
  • 域名:localhost

ASCII地址->整数地址

#include <arpa/inet.h>
int inet_aton(const char* straddr,struct in_addr* adrp);

返回:0表示转换不成功;1表示转换成功。

 

整数地址->ASCII地址

#include <arpa/inet.h>
char *inet_ntoa(struct in_addr inaddr);

返回:NULL编程转换不成功;其他返回值表示转换成功。

 

域名地址->整数地址

#include <netdb.h>
struct hostent *gethostname(const char *name);

 

整数地址->域名地址

#include <netdb.h>
struct hostent *gethostbyaddr(const char *addr,int len,int family);

 

字节转换

 存储字节的格式:

  • 网路字节顺序:高字节在前(Big Endian)
  • 本机字节顺序:低字节在前(Little Endian)

函数命名规律:

h代表字节顺序(本机顺序),n代表网络顺序(network)

//本地字节转化为网络字节顺序(长整数)
u_long PASCAL FAR htonl(IN u_long hostlong);
//本地字节转化为网络字节顺序(短整数)
u_short PASCAL FAR htons(IN u_short hostshort);
//网络字节转化为本地字节顺序(长整数)
u_long PASCAL FAR ntohl(IN u_long netlong);
//网络字节转化为本地字节顺序(短整数)
u_short PASCAL FAR ntohs(IN u_short netshort);

 

posted @ 2016-05-29 20:32  Msnow  阅读(644)  评论(0编辑  收藏  举报