winsocket入门学习

参考资料:http://c.biancheng.net/cpp/socket/

http://www.winsocketdotnetworkprogramming.com/


socket 是“套接字”意思,是计算机之间进行通信的一种约定。

通过 socket 这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据。

学习 socket,也就是学习计算机之间如何通信,并编写出实用的程序。




WD--返回WinSock的实现信息。

WD是一个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, FAR * LPWSADATA;



最简单的WinSocket程序

server.c

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#define BUFFER_SIZE 1024

int main()
{
	WSADATA		wsaData;			//包含系统所支持的WinSocket版本信息
	SOCKET		sServer;			//服务器Socket,用于监听客户端请求
	SOCKET		sClient;			//客户端Socket,用于实现与客户端的通信
	int			retVal;				//调用各种Socket函数的返回值
	char		buf[BUFFER_SIZE];	//用于接受客户端数据的缓冲区

	//初始化WinSocket 2.2
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
	{
		printf("WSAStartup failed!\n");
		return -1;
	}

	/**
	*  打印socket信息
	*  低位字节存储主版本号,高位字节存储副版本号
	*/
	printf("[wVersion] = %d.%d\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
	printf("[wHighVersion] = %d.%d\n", LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion));
	printf("[szDescription] = %s\n", wsaData.szDescription);
	printf("[szSystemStatus] = %s\n", wsaData.szSystemStatus);
	printf("[iMaxSockets] = %d\n", wsaData.iMaxSockets);
	printf("[iMaxUdpDg] = %d\n", wsaData.iMaxUdpDg);

	//创建用于监听的socket
	sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sServer == INVALID_SOCKET)
	{
		printf("socket failed!\n");
		WSACleanup();
		return -1;
	}
	
	/**
	*  设置服务器socket地址
	*  服务器监听地址为INADDR_ANY-->在任意本地地址(0.0.0.0)监听
	*  监听端口号为9999
	*/
	SOCKADDR_IN addrServ;
	addrServ.sin_family = AF_INET;
	addrServ.sin_port = htons(9999);
	addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

	//绑定Sockets Server到本地地址
	retVal = bind(sServer, (const struct sockaddr*)&addrServ, sizeof(SOCKADDR_IN));
	if (retVal == SOCKET_ERROR)
	{
		printf("bind failed!\n");
		closesocket(sServer);
		WSACleanup();
		return -1;
	}

	//在Sockets Server上进行监听
	retVal = listen(sServer, 1);
	if (retVal == SOCKET_ERROR)
	{
		printf("listen failed!\n");
		closesocket(sServer);
		WSACleanup();
		return -1;
	}

	//接受来自客户端的请求
	printf("TCP Server start...\n");
	struct sockaddr_in addrClient;
	int addrClientlen = sizeof(addrClient);
	sClient = accept(sServer, (struct sockaddr FAR *)&addrClient, &addrClientlen);
	if (sClient == INVALID_SOCKET)
	{
		printf("accept failed!\n");
		closesocket(sServer);
		WSACleanup();
		return -1;
	}

	//printf("%s\n", inet_ntoa(addrClient.sin_addr));

	while (1)
	{
		//清空接收数据的缓冲区
		memset(buf, 0, sizeof(buf));
		retVal = recv(sClient, buf, BUFFER_SIZE, 0);
		if (retVal == SOCKET_ERROR)
		{
			printf("recv failed\n");
			closesocket(sServer);
			closesocket(sClient);
			WSACleanup();
			return -1;
		}
		SYSTEMTIME st;
		GetLocalTime(&st);
		char szDateTime[50];
		sprintf(szDateTime, "%4d-%02d-%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay,
			st.wHour, st.wMinute, st.wSecond);
		
		//打印输出信息
		printf("%s, Recv From Client [%s:%d] :%s\n", szDateTime, inet_ntoa(addrClient.sin_addr), addrClient.sin_port, buf);
		
		if (strcmp(buf, "quit") == 0)
		{
			send(sClient, "quit", strlen("quit"), 0);
			break;
		}
		else
		{
			char msg[BUFFER_SIZE];
			sprintf(msg, "Message received - %s", buf);
			retVal = send(sClient, msg, strlen(msg), 0);
			if (retVal == SOCKET_ERROR)
			{
				printf("send failed\n");
				closesocket(sServer);
				closesocket(sClient);
				WSACleanup();
				return -1;
			}
		}
	}

	//清除工作
	closesocket(sServer);
	closesocket(sClient);
	WSACleanup();

	return 0;
}
client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#define BUFFER_SIZE 1024

int main()
{
	WSADATA		wsaData;
	SOCKET		sHost;
	int			retVal;
	char		buf[BUFFER_SIZE];

	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
	{
		printf("WSAStartup failed!\n");
		return -1;
	}


	sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sHost == INVALID_SOCKET)
	{
		printf("socket failed!\n");
		WSACleanup();
		return -1;
	}
	
	SOCKADDR_IN addrServ;
	addrServ.sin_family = AF_INET;
	addrServ.sin_port = htons(9999);
	addrServ.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	
	retVal = connect(sHost, (LPSOCKADDR)&addrServ, sizeof(SOCKADDR_IN));
	if (retVal == SOCKET_ERROR)
	{
		printf("connect failed!\n");
		closesocket(sHost);
		WSACleanup();
		return -1;
	}

	
	while (1)
	{
		printf("Please input a string:");
		gets(buf);
		retVal = send(sHost, buf, strlen(buf), 0);
		if (retVal == SOCKET_ERROR)
		{
			printf("send failed!\n");
			closesocket(sHost);
			WSACleanup();
			return -1;
		}
		memset(buf, 0, sizeof(buf));
		retVal = recv(sHost, buf, sizeof(buf), 0);
		if (retVal == SOCKET_ERROR)
		{
			printf("recv failed!\n");
			closesocket(sHost);
			WSACleanup();
			return -1;
		}
		printf("Recv From Server: %s\n", buf);
		if(strcmp(buf, "quit") == 0)
		{
			break;
		}
	}

	//วๅณนคื๗
	closesocket(sHost);
	WSACleanup();

	return 0;
}

对于完成的client/server程序可以使用NC来测试

1)连接到 remote 主机,例子:
格式:nc -nvv 192.168.x.x 80
讲解:连到192.168.x.x的TCP80端口

2)监听 local 主机,例子:
格式:nc -l -p 80
讲解:监听本机的TCP80端口



posted @ 2016-09-13 09:45  N3verL4nd  阅读(218)  评论(0编辑  收藏  举报