使用基本的socket函数
Posted Autumn の Box
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用基本的socket函数相关的知识,希望对你有一定的参考价值。
1.socket库的2.2版本的文件:
dll文件:ws2_32.dll
lib文件:ws2_32.lib
头文件:<WINSOCK2.H>
2.socket库的初始化和卸载
2.1-初始化socket库
int WSAStartup (
WORD wVersionRequested, //请求使用的库的版本
LPWSADATA lpWSAData //返回可用的库的信息
);
2.2-卸载socket库
WSACleanup();
2.3-MFC提供了一个AfxSocketInit函数,该函数内部自动调用了WSAStartup函数和WSACleanup函数,利用该函数加载和卸载socket库时,不需要为工程连接ws2_32.lib库文件,仅需包含头文件:#include <Afxsock.h>,且必须在应用的程序类的InitInstance函数中调用该函数,该函数加载的是1.1版本的socket库;
BOOL AfxSocketInit( WSADATA* lpwsaData = NULL );
返回值:函数调用成功返回非0值,调用失败返回0;
3.TCP通信
3.1-TCP服务器
1--创建服务器端socket
SOCKET socket (int af, int type, int protocol);
af:指定地址族,AF_UNIX/AF_LOCAL/AF_FILE--本地通信;AF_INET--网络通信IPv4(主用);AF_INET6--网络通信IPv6(前缀AF替换成PF效果一样);
type:指定socket类型,SOCK_STREAM--流式套接字,SOCK_DGRAM--数据报式套接字;
protocol:推荐为0;
函数返回值:成功返回socket描述符;失败返回一个INVALID_SOCKET值,错误信息可通过WSAGetLastError函数返回;
2--绑定IP地址和端口(bind)
int bind (SOCKET s, const struct sockaddr FAR* name, int namelen);
s:要绑定的套接字;
name:指定该套接字的通信地址信息,指向sockaddr结构体或sockaddr_un结构体或sockaddr_in结构体的指针变量;
nameLen:指定地址结构的长度;
函数返回值:成功返回0;失败返回一个SOCKET_ERROR,错误信息可通过WSAGetLastError函数返回;
通信地址包括结构体:
struct sockaddr --主要用于做函数的参数,不负责存储数据;
struct sockaddr {
unsigned short sa_family; //指定地址族
char sa_data[14]; //要求一块内存分配区,起占位作用
};
struct sockaddr_in --负责存储网络通信的地址数据
struct sockaddr_in{
short sin_family; //指定地址族
unsigned short sin_port; //端口号
struct in_addr sin_addr; //主机IP地址
char sin_zero[8];
};
注:若本地机器具有多个网卡,则每个网卡均有自己的IP地址,可将IP地址指定为INADDR_ANY,允许向分配给本地机器的各个IP地址发送或接收数据;
3--监听(listen)
int listen ( SOCKET s, int backlog );
s:套接字;
backlog:SOMAXCONN,设置等待队列的最大长度(可接收的请求个数);
4--等待客户端连接并接受(accept)
SOCKET accept ( SOCKET s, struct sockaddr FAR* addr, int FAR* addrlen );
s:套接字;
addr:指向一个缓冲区,该缓冲区用来保存服务器端接受的发起连接的客户端的IP地址信息和端口信息;
addrlen:返回包含地址信息的长度;
函数返回值:成功返回socket描述符;失败返回一个INVALID_SOCKET值,错误信息可通过WSAGetLastError函数返回;
5--数据收发(send/recv)
int send ( SOCKET s, const char FAR * buf, int len, int flags );
s:套接字;
buf:指向一个缓冲区,该缓冲区包含将要传递的数据;
len:缓冲区的长度;
flags:设为0;
int recv ( SOCKET s, char FAR* buf, int len, int flags );
s:套接字;
buf:指向一个缓冲区,用来保存接收的数据;
len:缓冲区的长度;
flags:设为0;
6--关闭socket
int closesocket ( SOCKET s );
通过netstat -an,查看网络端口状态
3.2-TCP客户端
1--创建客户端socket
2--连接服务器,如果是本机 inet_addr("127.0.0.1");
int connect ( SOCKET s, const struct sockaddr FAR* name, int namelen );
s:套接字;
name:设定连接的服务器端地址信息;
namelen:指定服务器端地址的长度;
3--数据收发(send/recv)
4--关闭socket
4.UDP通信
4.1-UDP服务器
1--创建服务器端socket
2--绑定IP地址和端口(bind)
3--数据收发 recvfrom/sendto
int recvfrom ( SOCKET s, char FAR* buf, int len, int flags, struct sockaddr FAR* from, int FAR* fromlen );
s:套接字;
buf:指向一个缓冲区,用来接收数据;
len:缓冲区的长度;
flags:设为0;
from:指向地址结构体,用来接收发送数据方的地址信息;
fromlen:调用前须给一个初始值,函数调用后会返回地址结构的大小;
int sendto ( SOCKET s, const char FAR * buf, int len, int flags, const struct sockaddr FAR * to, int tolen );
s:套接字;
buf:指向一个缓冲区,包含将要发送的数据;
len:指定缓冲区中数据的长度;
flags:设为0;
to:可选指针,指定目标套接字的地址;
tolen:参数to指定的地址的长度;
4--关闭socket
4.2-UDP客户端
1--创建客户端socket
2--数据收发 sendto/recvfrom
3--关闭socket
5.IP地址格式和端口格式的转换
5.1-IP地址格式的转换
将点分十进制的IP地址转为十六进制的格式:
unsigned long inet_addr ( const char FAR * cp );
将IP地址从十六进制转为点分十进制的格式:
char FAR * inet_ntoa ( struct in_addr in );
5.2-端口格式的转换
将本机端口的整数格式转为TCP/IP网络整数格式:
u_short htons ( u_short hostshort ); //16位
u_long htonl ( u_long hostlong ); //32位
将端口的网络整数格式转为本地端口的整数格式:
u_short ntohs ( u_short netshort );
5.3-主机名<-->IP地址
5.3.1主机名转换为IP地址
函数gethostbyname从主机数据库中获取主机名相对应的IP地址;
struct hostent FAR * gethostbyname ( const char FAR * name );
name:指向一个主机名字符串;
返回值:函数返回hostent结构体类型的指针,该结构体类型的定义如下:
struct hostent {
char FAR * h_name;
char FAR * FAR * h_aliases;
short h_addrtype;
short h_length;
char FAR * FAR * h_addr_list;
};
该结构体的最后一个成员h_addr_list是一个指针数组,它的每个元素都是一个字符指针,指向内存中存放的一个个点分十进制表示的主机IP地址,一台主机可能会有多个IP地址;
5.3.2IP地址转换为主机名
函数gethostbyaddr将根据指定的IP地址获取相应的主机信息;
struct HOSTENT FAR * gethostbyaddr (
const char FAR * addr,
int len,
int type
);
addr:是一个指向点分十进制类型的IP地址的指针;
len:地址长度;对于AF_INET地址族,长度必须为4个字节;
type:地址类型,Windows平台下必须设为AF_INET;
返回值:函数也是返回hostent结构体类型的指针,结构体中的h_name数据成员就是主机名;
以上是关于使用基本的socket函数的主要内容,如果未能解决你的问题,请参考以下文章