• 学习:WinSock TCP 短连接


    TCP Socket编程概念:

    服务端程序:创建socket -> bind -> listen -> accept -> recv/send -> close

    客户端程序:创建socket -> connect -> recv/send -> close

    流式套接字:
    1、TCP/IP
    2、SOCK_STREAM

    网络程序 = 客户端 + 服务端

    套接字 socket = IP + PORT

    IP地址的转换

    inet_ntoa : 功能是将网络地址转换成"."点隔的字符串格式
    inet_aton : 将字符串形式的IP地址 转换 为一个32位的网络序列IP地址
    inet_addr : 将字符串形式的IP地址 转换 为一个网络字节顺序的整型值
    

    字节转换

    ntohl()    // 网络字节顺序转换为主机字节顺序 long 类型
    ntohs()    // 网络字节顺序转换为主机字节顺序 short 类型
    htonl()    // 主机字节顺序转换为网络字节顺序 long 类型
    htons()    // 主机字节顺序转换为网络字节顺序 short类型
    
    注意:如果主机字节顺序是大端,那么转换为网络字节顺序的时候,那么转换后,仍然是大端的字节顺序。
    

    C/S通信示例图如下:


    实现代码:

    服务端:

    #include<winSock2.h>
    #include<iostream>
    #pragma comment(lib, "ws2_32.lib") //添加动态链接库
    
    using namespace std;
    
    int main(int argc, char * argv[]) {
    	const int	BUFSIZE = 1024;
    	SOCKET		ListeningSocket; //定义一个套接字变量
    	SOCKET		NewConnection; //客户端的请求生成的新的套接字
    	SOCKADDR_IN ClientAddr;
    	SOCKADDR_IN ServerAddr;
    	char		Message[BUFSIZE];
    	int			ClientAddrLen;
    	ZeroMemory(Message, BUFSIZE);
    	
    	if (argc <= 1)
    	{
    		cout << "USAGE: TcpServer <Listen Port>" << endl;
    		return -1;
    	}
    
    	
    	int ret; //用来检查初始化成功是否
    	WSADATA wsaDATA; // 创建一个WSADATA 用来初始化套接字网络库
    	
    	if ( (ret = WSAStartup(MAKEWORD(2,2), &wsaDATA)) != 0) { // 初始化套接字网络库WinSock2.2版本
    		cout << "WSAStartup初始化失败 with error " << ret << endl;
    		return -1;
    	}
    
    	//创建套接字 AF_INET协议 SOCK_STREAM流 TCP协议
    	if ((ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == SOCKET_ERROR) {
    		cout << "创建套接字失败 with error " << WSAGetLastError() << endl;
    		WSACleanup();
    		return -1; 
    	}
    
    	//绑定套接字
    	ServerAddr.sin_family = AF_INET;
    	ServerAddr.sin_port = htons(atoi(argv[1]));
    	ServerAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    
    	if (bind(ListeningSocket, (SOCKADDR *)&ServerAddr, sizeof(SOCKADDR)) == SOCKET_ERROR) {
    		cout << "绑定套接字失败 with error " << WSAGetLastError() << endl;
    		closesocket(ListeningSocket);
    		WSACleanup();
    		return -1;
    	}
    	 
    	//监听套接字
    	if((ret = listen(ListeningSocket, 1)) == SOCKET_ERROR) {
    		cout << "监听套接字失败 with error " << WSAGetLastError() << endl;
    		closesocket(ListeningSocket);
    		WSACleanup();
    		return -1;
    	}
    	cout << "正在监听端口"<< argv[1] << "中..." << endl;
    
    
    	//接收客户端数据
    
    	ClientAddrLen = sizeof(SOCKADDR);
    
    	if((NewConnection = accept(ListeningSocket,(SOCKADDR*)&ClientAddr, &ClientAddrLen)) == INVALID_SOCKET){//创建一个当前客户端和服务端的套接字
    		cout << "创建NewConnection失败 with error " << WSAGetLastError() << endl;
    		closesocket(ListeningSocket);
    		WSACleanup();
    		return -1;
    	}
    
    	//关闭套接字
    	closesocket(ListeningSocket);
    
    	recv(NewConnection, Message, sizeof(Message), 0);
    	cout << "接收到的数据为:" << Message << endl;
    
    
    	closesocket(NewConnection);
    	WSACleanup();
    	
    
    	return 0;
    }
    

    客户端:

    #include<WinSock2.h>
    #include<iostream>
    #pragma comment(lib, "ws2_32.lib") //添加动态链接库
    #pragma warning(disable:4996) //忽略旧函数使用缺陷的警告
    
    using namespace std;
    
    int main(int argc, char * argv[]) {
    	const int	BUFSIZE = 1024;
    	SOCKET		ClientSocket;
    	SOCKADDR_IN ServerAddr;
    	char		SendBuf[BUFSIZE];  //发送存储的数据缓冲区
    	char		BufRecv[BUFSIZE]; //接收收到的数据缓冲区
    	
    	ZeroMemory(SendBuf, BUFSIZE);
    	ZeroMemory(BufRecv, BUFSIZE);
    	strcpy(SendBuf, "Hello, My Name is Client");
    
    	if (argc <= 2)
    	{
    		cout << "USAGE: TcpServer <Server IP> <Server PORT>" << endl;
    		return -1;
    	}
    
    	WSADATA		WSAData;
    	int			ret;
    	if ((ret = WSAStartup(MAKEWORD(2, 2), &WSAData)) != 0) {
    		cout << "WSAStartup初始化失败 with error " << ret << endl;
    		return -1;
    	}
    	
    
    	//创建套接字
    	if ((ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == SOCKET_ERROR) {
    		cout << "创建套接字失败 with error " << WSAGetLastError() << endl;
    		WSACleanup();
    		return -1;
    	}
    
    	//连接connet服务端
    	ServerAddr.sin_family = AF_INET;
    	ServerAddr.sin_addr.s_addr = inet_addr(argv[1]);
    	ServerAddr.sin_port = htons(atoi(argv[2]));
    	if (connect(ClientSocket, (SOCKADDR *)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR) {
    		cout << "连接服务端失败 with error " << WSAGetLastError() << endl;
    		closesocket(ClientSocket);
    		WSACleanup();
    		return -1;
    	}
    
    	cout << "连接建立成功!";
    
    
    	//send发送数据
    	if ((ret = send(ClientSocket, SendBuf, strlen(SendBuf), 0)) == SOCKET_ERROR){
    		cout << "send failed with error " << WSAGetLastError() << endl;;
    		closesocket(ClientSocket);
    		WSACleanup();
    		return -1;
    	}
    
    	//关闭套接字
    	closesocket(ClientSocket);
    	WSACleanup();
    	return 0;
    }
    

    结果图:

  • 相关阅读:
    一个人的旅行 dij(),评测的时候有点惨
    CodeFroce Round 340 div2 E XOR and Favorite Number【莫队算法】
    [HihoCoder-1185] 连通性·三 【tarjan+缩点】
    2017百度之星初赛(A)1001,1005,1006解题报告
    HDU 5961&AOJ 821 传递
    pair
    优先队列 priority_queue
    ccf 201903-5
    memset 和 fill 的区别
    ccf 20190302
  • 原文地址:https://www.cnblogs.com/zpchcbd/p/12171681.html
Copyright © 2020-2023  润新知