此处引用他人博客原话
在server端的流程一般如下:
1、初始化winsocket
2、建立socket
3、与本机进行邦定(bind)
4、开始监听(listen)
5、然后与客户端建立连接(accept)
6、然后与客户端进行通信(send, recv)
7、当通信完成以后,关闭连接
8、释放winsocket的有关资源
在Client端的流程一般如下:
1、初始化winsocket
2、建立socket
3、与本机进行邦定(bind)
4、与服务器进行连接(connect)
5、与服务器进行通信(send, recv)
6、当通信完成以后,关闭连接
7、释放winsocket占用的资源
1. 初始化winsocket
需要先初始化WSADATA
这个数据结构
typedef struct WSAData {
WORD wVersion;
WORD wHighVersion;
#ifdef _WIN64
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR * lpVendorInfo;
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
#else
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR * lpVendorInfo;
#endif
} WSADATA;
然后需要调用MAKEWORD(2,2)
指明版本,高位字节中存储副版本号,低位字节存储主版本号
最后调用int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
,第一个参数指明版本号,第二个参数放入WSADATA声明的引用,若成功则返回0
2. 建立socket
调用SOCKET socket(int af,int type,int protocol);
来建立socket
-
af
:一个地址描述。目前仅支持AF_INET
格式,也就是说ARPA Internet地址格式 -
type
:指定socket类型。新套接口的类型描述类型,如TCP(SOCK_STREAM)和UDP(SOCK_DGRAM)。常用的socket类型有,SOCK_STREAM
、SOCK_DGRAM
、SOCK_RAW
、SOCK_PACKET
、SOCK_SEQPACKET
等等 -
protocol
:顾名思义,就是指定协议。套接口所用的协议。如调用者不想指定,可用0。常用的协议有,IPPROTO_TCP
、IPPROTO_UDP
、IPPROTO_STCP
、IPPROTO_TIPC
等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议 -
返回
SOCKET
对象
3. 与本机进行绑定
绑定前要先声明结构SOCKADDR_IN
,并给它的成员赋值
struct sockaddr_in {
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
sin_family
指代协议族,在socket编程中只能是AF_INET
sin_port
存储端口号(使用网络字节顺序)sin_addr
存储IP地址,使用in_addr
这个数据结构sin_zero
是为了让sockaddr
与sockaddr_in
两个数据结构保持大小相同而保留的空字节。
其中,sin_port
的赋值需要使用htons
函数,用法如下:
SOCKADDR_IN sockaddr;
sockaddr.sin_port = htons(MY_PORT);
htons
的作用是 “Host to Network Short” ,即将本机表达方式转换成网络字节顺序的short整型
sin_addr
的赋值如下:
SOCKADDR_IN sockaddr;
sockaddr.sin_addr.s_addr = inet_addr(IP_ADDRESS);//或者htonl(INADDR_ANY);,这里表示本机IP地址
对SOCKADDR_IN
声明的结构体赋值完成后,调用
int bind(SOCKET sockfd, const sockaddr *my_addr, int addrlen);
来进行绑定
4. 开始监听
调用int listen(SOCKET sockfd, int backlog);
来监听是否有连接
其中backlog
是可同时连接数
5. 建立连接
调用SOCKETaccept(SOCKET sockfd, void *addr, int *addrlen);
来接受连接,并获取一个套接字
7. 关闭连接
int closesocket( SOCKET s);
8. 释放资源
int WSACleanup();
一个不成熟的实例
Client.cpp
#include "pch.h"
#include <iostream>
#include <WinSock2.h>
#include <string>
#include <stdlib.h>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
int main()
{
WSADATA wsadata;
SOCKET s;
SOCKADDR_IN ServerAddr;
int Port