1. 创建 控制台 TCP 服务端程序步骤

来源:互联网 发布:鬼吹灯和盗墓笔记 知乎 编辑:程序博客网 时间:2024/06/05 02:48
一、创建控制台服务端的步骤:
1.启动 WinSock DLL -------> WSAStartup
2.创建套接字 Socket
3.绑定套接字和本地IP bind
4.将套接字设置为监听模式 listen
5.接收客户端的请求产生连接套接字 accepte

6.发送消息给客户端 send

7.接收客户端发送过来的消息 recv---->(关闭连接套接字 closesocket)


二、创建客户端步骤
1.启动 WinSock DLL -------> WSAStartup
2.创建套接字 Socket
3.建立连接 connect
4.接收消息 recv 发送消息 send
5.关闭套接字 closesocket 
6.终止对套接字库的使用 WSACleanup();





1.第一步使用 WSAStartup 函数启动 WinSock DLL
WSAStartup Function: The WSAStartup function initiates use of the Winsock DLL by a process. 
(1)必要条件 #include <Winsock2.h> , 动态链接添加 ws2_32.lib(链接器->输入->附加依赖项 中添加 .lib)


(2)WSAStartup 函数介绍:


int WSAStartup(
  __in   WORD wVersionRequested,// WORD-->unsigned short(两个字节 16位 0~65535)
  __out  LPWSADATA lpWSAData // 输出信息,有关信息存储在这个结构体中
);
//第一个参数: wVersionRequested:指定呼叫者(客户端)可以使用的Windows Socket 的最高版本,高位字节代表 副版本号,低位字节代表 主版本号
// 可以使用的版本号(1.0, 1.1, 2.0, 2.1, 2.2)
// Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h 


//第二个参数: lpWSAData: 一个指向结构体 WSAData 的指针,结构体信息如下:


typedef struct WSAData {
  WORD           wVersion; // Windows Sockets specification 版本信息,高位字节 副版本,低位字节 主版本
  WORD           wHighVersion;// Ws2_32.dll 所能支持的 Windows Sockets specification 最高版本
  char           szDescription[WSADESCRIPTION_LEN+1];
  char           szSystemStatus[WSASYS_STATUS_LEN+1];
  
  unsigned short iMaxSockets; // 这个一般不用
  unsigned short iMaxUdpDg; // 这个一般不用
  char FAR       *lpVendorInfo;
} WSADATA, *LPWSADATA;


2.使用 socket 函数 创建套接字,这一步创建的套接字用于监听


SOCKET WSAAPI socket(
  __in  int af,//The address family specification. 我们一般使用 AF_INET(指定IP规范为 IPV4)
  __in  int type,// 套接字规范 一般是用流式套接字 SOCK_STREAM
  __in  int protocol // 协议 如果设定为 0 ,表示根据套接字自动选择协议,可用的有 IPPROTO_TCP IPPROTO_UDP 等
);


3.使用 bind 函数将上面创建的套接字与本地IP和端口号进行绑定


The bind function associates a local address with a socket. 
// bind函数将本地 IP 地址与一个套接字 socket 进行绑定


int bind(
  __in  SOCKET s,// 将被绑定的 socket
  __in  const struct sockaddr *name,//指向结构体 sockaddr 的指针
  __in  int namelen // 第二个参数中结构体的长度
);


struct sockaddr
{
u_short sa_family;
char sa_data[14];
};
sa_family:指定该地址家族,在这里必须使用 AF_INET(IPV4)
sa_data:仅仅是表示要求一块内存分配区,起到占位的作用,该区域中指定与协议相关的具体地址信息。由于实际要求的只
是内存区,所以对于不同的协议家族,用不同的结构来替换 sockaddr,除了 sa_family 外,sockaddr 是按网络字节顺序
表示的。在TCP/IP 中,我们可以用 sockaddr_in 结构替换 sockaddr,以方便我们填写地址信息。


struct sockaddr_in
{
short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};


sin_family:地址族,对于IP地址,sin_family 成员将一直是 AF_INET
sin_port:将要分配给套接字的端口,大于 1024
sin_addr:给出的是套接字的主机IP地址
sin_zero:只是一个填充数,使 sockaddr_in 结构和 sockaddr 结构的长度一样


如果 bind 函数调用成功,返回0,失败返回 SOCKET_ERROR 
错误信息可以通过WSAGetLastError 函数返回


4.监听 listen
int listen(
  __in  SOCKET s,
  __in  int backlog
);
监听成功返回 0


5.accepte 接收请求


6.send 发送消息


7.recv 接收消息


#include #include void main(){//---------------------------------------------------------------------------------------------------------------// 使用函数 WSAStartup 启动 WinSock DLL//---------------------------------------------------------------------------------------------------------------WORD wVersionRequested;WSADATA wsaData; // 创建一个 WSADATA 结构体的变量, 这个变量是用来接收                  // Windows Sockets implementation. 的信息的int err = 0; // 用来接收错误信息的/*Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */wVersionRequested = MAKEWORD(1, 1); // Window Socket application 1.1err = WSAStartup(wVersionRequested, &wsaData); // 创建成功返回 0// 如果 启动 WinSock DLL 不成功if (err != 0){return;}// 如果版本信息与设置的不相同if (HIBYTE(wsaData.wVersion) != 1 || LOBYTE(wsaData.wVersion) != 1){return;}//---------------------------------------------------------------------------------------------------------------// 使用函数 socket 创建套接字 , 然后使用函数 bind 将套接字与本地IP和端口进行// 绑定,使用 listen 监听//---------------------------------------------------------------------------------------------------------------SOCKET socSrv = socket(AF_INET,SOCK_STREAM,0); // 准备用来监听的套接字// 绑定套接字,设置地址族信息SOCKADDR_IN addrSrv;addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//htonl()将主机数转换成无                                                 //符号长整形的网络字节顺序addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(6000); // 端口号// 绑定 socketbind(socSrv,(SOCKADDR *)&addrSrv,sizeof(SOCKADDR));// 监听listen(socSrv,5); // 意思是开启监听且最多可以监听5个SOCKADDR_IN addrClient; // 用来存储连接上的客户端的地址族信息int len = sizeof(SOCKADDR);// accept 接收请求while (1){// 创建连接套接字SOCKET sockConn = accept(socSrv, (SOCKADDR *)&addrClient, &len); // 发送数据char sendBuf[100];sprintf(sendBuf,"客户端的地址:%s",inet_ntoa(addrClient.sin_addr));send(sockConn,sendBuf,strlen(sendBuf) + 1, 0); // 接收数据char recvBuff[100];recv(sockConn,recvBuff,100,0);printf("%s\n",recv);// 关闭连接套接字closesocket(sockConn);}}//---------------------------------------------------------------------------// 客户端程序#include #include #include void main(){//---------------------------------------------------------------------------------------------------------------// 使用函数 WSAStartup 启动 WinSock DLL//---------------------------------------------------------------------------------------------------------------WORD wVersionRequested;WSADATA wsaData; // 创建一个 WSADATA 结构体的变量, 这个变量是用来接收 Windows Sockets implementation. 的信息的int err = 0; // 用来接收错误信息的/*Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */wVersionRequested = MAKEWORD(1, 1); // Window Socket application 1.1err = WSAStartup(wVersionRequested, &wsaData); // 创建成功返回 0// 如果 启动 WinSock DLL 不成功if (err != 0){return;}// 如果版本信息与设置的不相同if (HIBYTE(wsaData.wVersion) != 1 || LOBYTE(wsaData.wVersion) != 1){return;}//---------------------------------------------------------------------------------------------------------------// 使用函数 socket 创建套接字 //---------------------------------------------------------------------------------------------------------------SOCKET socClient = socket(AF_INET,SOCK_STREAM,0);// 客户端不需要绑定 可以直接连接服务端 connectSOCKADDR_IN addrSrv;addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(6000);// 建立连接connect(socClient,(SOCKADDR *)&addrSrv,sizeof(SOCKADDR));char recvBuf[100];recv(socClient,recvBuf,100,0);printf("%s\n",recvBuf);send(socClient,"This is Zhangsan",strlen("This is Zhangsan")+1,0);system("pause");closesocket(socClient);WSACleanup(); // 终止对套接字库的使用}