C/C++ socket套接字(Windows)怎么用

0

C/C++ socket套接字(Windows)怎么用?想了解一下。

ava
lovely_ckj

2019-11-4

5

早年 VC6 收录的笔记,不知现在还是否可用,可参考参考 ... 

服务端:

#include <stdio.h> 
#include <Winsock2.h> 
#include <iostream>
using namespace std;

#pragma comment(lib, "ws2_32.lib")
#pragma warning ( disable : 4996 )

void main() 
{ 
	WORD wVersionRequested; 
	WSADATA wsaData; 
	int err; 
	
	// 高字节-副版本,低字节-主板本
	wVersionRequested = MAKEWORD( 1, 1 ); 
	
	// 初始化 Winsock 服务,必须第一个调用
	// 第一个参数指明程序请求使用的Socket版本
	// 将某个版本填充进 wasDate 结构对象
	err = WSAStartup( wVersionRequested, &wsaData );		// 函数成功则返回 0
	if ( err != 0 )
		return; 
	
	if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 )
	{
		WSACleanup(); 
		return; 
	}

	// AF_INET 指定:TCP、UDP 协议传输
	// SOCK_STREAM 指定用 AF_INET 中的 TCP 传输
	SOCKET sockSrv = socket( AF_INET, SOCK_STREAM, 0 );
	
	/***** 填充结构,用在 bind、connect、recvfrom、sendto() 函数 *****/

	SOCKADDR_IN addrSrv; 

	// 服务器监听 6000 端口,客户端那里就新建一个 socket 与 6000 值的端口进行链接,该服务器就会 accept() 到那个链接了
	// 貌似也可以写成 addrSrv.sin_addr.S_addr = inet_addr( "127.0.0.1" );	之类的

	// 服务端不用指定自己的 ip 的,直接设置 any 任何ip 即可。 这样在客户端使用服务端的 公网 ip socket 即可
	addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);	// 使用自己或其它的 ip 地址,htons() 将数字转换成网络数据格式
	addrSrv.sin_family = AF_INET;  
	addrSrv.sin_port = htons(6000);			// 端口号
	
	// sockaddr_in和sockaddr是并列的结构,指向sockaddr_in的结构体的指针也可以指向 sockaddr的结构体
	// 将套接字与端口之类的绑定,才能监听端口
	bind( sockSrv, (SOCKADDR*)&addrSrv ,sizeof(SOCKADDR) ); 
	
	// 使套接字处于监听状态
	listen( sockSrv, 5 );		// 最多允许 5 台主机链接
	
	SOCKADDR_IN addrClient; 
	int len = sizeof(SOCKADDR);

	while(1) 
	{ 
		// 等待一个主机的接入,并填充 addrClient 结构,储存了客户机的信息
		SOCKET sockConn = accept( sockSrv, (SOCKADDR*)&addrClient, &len );

		char sendBuf[50]; 
		sprintf( sendBuf, "Welcome %s to here!", inet_ntoa(addrClient.sin_addr) ); 

		// 6000 只是用来确定该服务器与客户端需要链接!!
		cout << addrClient.sin_port << endl;		// 输出的不是客户端设置的 6000,而是一个系统分配给它的一个可用端口!1
		
		cout << "我在等客户机发送消息过来" << endl;

		// 阻塞式接受消息!!客户端必须有消息发送过来、或者客户端 退出。才会继续!!!!
		char recvBuf[50]; 
		recv( sockConn, recvBuf, 50, 0 );		// 一直停着监视 sockConn 链接,客户端有消息过来、或关闭之类的动作才会继续

		// 给客户机发送消息
		send( sockConn, sendBuf, strlen(sendBuf) + 1, 0 );
		
		printf( "%s\n", recvBuf ); 
		closesocket( sockConn ); 
	} 
	
}

客户端:

#include <stdio.h>
#include <Winsock2.h>
#include <iostream>
using namespace std;

#pragma comment(lib, "ws2_32.lib")

void main()
{
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	
	wVersionRequested = MAKEWORD( 1, 1 );
	
	err = WSAStartup( wVersionRequested, &wsaData );
	if ( err != 0 )
		return;
	
	if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 )
	{
		WSACleanup( );
		return;
	}
	// sockClient 不是代表主机,而是代表这个主机与服务器之间的链接线路。
	// 向该链接 sockClient 发送消息就是发送给服务器
	// 与服务器的 SOCKET socket = accept( socketSer... ) 相对应,但不相等;
	// 同理,服务器向 socket 发送消息也就是发送给客户端了
	SOCKET sockClient = socket( AF_INET, SOCK_STREAM, 0 );

	SOCKADDR_IN addrSrv;
	addrSrv.sin_addr.S_un.S_addr = inet_addr( "127.0.10.1" );
	addrSrv.sin_family = AF_INET;
	addrSrv.sin_port = htons( 6000 );		// 监听端口,需与服务器的相同

	// 将主机与服务器链接,因为有个服务器监听的就是 6000 端口,所以此时服务器的 accept() 会返回一个 socket
	connect( sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR) );

	// 给主机的 socket 发送消息就是给服务器发送消息
	send( sockClient, "hello", strlen("hello") + 1, 0 );

	char recvBuf[50] = {0};
	recv( sockClient, recvBuf, 50, 0 );
	
	printf("%s\n",recvBuf);
	
	closesocket(sockClient);
	WSACleanup();
}
ava
xiongfj ◑◑

2019-11-4

技术讨论社区