本文很多内容 转载自WinSocket
C/S 通信过程
头文件
WinSock.h
WinSock2.h 兼容第一版本的WinSock.h,并且支持异步。
参数说明
1.AF等实参
选择 AF_INET 的目的就是使用 IPv4 进行通信。因为 IPv4 使用 32 位地址,相比 IPv6 的 128 位来说,计算更快,便于用于局域网通信
2. sockaddr
详细出处 百度百科
struct sockaddr_in { // winsock2.h 定义
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
typedef struct in_addr
{
union{
struct { unsigned char s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { unsigned short s_w1,s_w2; } S_un_w;
unsigned long S_addr; //s_addr按照网络字节顺序存储IP地址
}S_un;
}in_addr;
sin_family :指代协议族,在socket编程中只能是AF_INET
sin_port :存储端口号(使用网络字节顺序),在linux下,端口号的范围 :0~65535,同时0~1024范围的端口号已经被系统使用或保留。
sin_addr :存储IP地址,使用in_addr这个数据结构 ????(没懂!,搜了半天)
sin_zero :是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。
函数解释
1.WASStartup
初始化套接字环境,本函数必须是应用程序或DLL调用的第一个Windows Sockets函数.它允许应用程序或DLL指明Windows Sockets API的版本号及获得特定Windows Sockets实现的细节.应用程序或DLL只能在一次成功的WSAStartup()调用之后才能调用进一步的Windows Sockets API函数.
//begin 初始化网络环境
int m_WSAerr = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(NO_ERROR!=m_iWSAerr)
{
printf("WSAStartup failed with error: %d\n", m_iWSAerr);
return -1;
}//end
2.Clearup:
清理套接字环境,和上面的WSAStartup相反,该函数是在程序不在对任何Windows Sockets函数调用后,用其来清理套接字环境的
int WSACleanup (void);
3、SOCKET socket(int af, int type, int protocol);
建立套接字
参数af用于指定网络地址类型,一般取AF_INET,表示该套接字在Internet域中,进行通信。
参数type用于知道套接字的类型,若取SOCK_STREAM表示创建的套接字是流套接字,而取SOCK_DGRAM创建数字报套接字。
参数protocol用于指定网络协议,一般取0,表示默认为TCP/IP协议。 若套接字创建成功则该函数返回创建的套接字句柄SOCKET,否则产生INVALID_SOCKET错误。
//begin socket 一个套接字
hTcpSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == hTcpSocket)
{
MJS_LOG_ERROR("socket failed with error: \n");
WSACleanup();
return -1 ;
}//end
4 int listen(SOCKE s, int backlog)
将套接字置入监听模式并准备接受连接请求。
参数s是服务器端套接字;
参数backlog是accept阻塞队列的长度。
如无错误发生,listen函数返回0,失败则返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码
5、SOCKET accept( SOCKET s, struct sockaddr* addr, int* addrlen )
参数s同上;
addr是一个有效的SOCKADDR_IN结构的地址;
addrlen是sockaddr_in结果的长度。
accept函数返回后,addr参数变量中会包含发出连接请求的那个客户机的IP地址信息,而addrlen参数则指出该结构的长度,并返回一个新的套接字描述符,它对应于已经接受的那个客户机连接。
6.int bind( SOCKET s, const struct sockaddr* name, int namlen )
绑定到本地,name中指定的IP应该是当前运行该程序机器的IP。
7.int connect( SOCKET s, const struct sockaddr FAR* name, int namelen )
连接到服务器
8. int send( SOCKET s, const char* buf, int len, int flags )
失败时返回 -1/SOCKET_ERROR
sockfd:已建立连接的发送端套接字描述符(非监听描述符)
buf:应用要发送数据的缓存
len:实际要发送的数据长度
flags:一般设置为0。 flags可取的值有:0、MSG_DONTROUTE或MSG_OOB或这些标志的按位或运算。
9、int recv( SOCKET s, char* buf, int len, int flags );
表示从接收缓冲区拷贝数据
s是准备接收数据的套接字
buf是即将收到数据的字符缓冲区
len则是准备接受的字节数或buf缓冲的长度
flags一般指定为0.参数可以是0、MSG_PEEK或MSG_OOB或这些标志的按位“或”运算。
成功时,返回拷贝的字节数,失败返回-1。阻塞模式下,recv/recvfrom将会阻塞到缓冲区里至少有一个字节(TCP)/至少有一个完整的UDP数据报才返回,没有数据时处于休眠状态。若非阻塞,则立即返回,有数据则返回拷贝的数据大小,否则返回错误-1,置错误码为EWOULDBLOCK。
10、int shutdown( SOCKET s, int how );
其中,how参数用于描述禁止哪些操作,它可取的值有:SD_RECEIVE、SD_SEND或SD_BOTH。 如果是SD_RECEIVE,就表示不允许再调用接收函数, 如果选择SD_SEND,表示不允许再调用发送函数, 如果是SD_BOTH, 则表示取消连接两端的收发操作。 如果没有错误发生,shutdown()返回0,否则返回SOCKET_ERROR错误。
11、 int closesocket(SOCKET s );
s是要关闭的套接字描述字,再利用套接字执行调用就会失败。
12 int gethostname(char *name, size_t len):
这个函数,调用后,会将主机名保存在name里面。而len是name的大小。该函数返回0表示成功,否则失败。