winsock编程基础

今天复习了一下计算机网络的知识,就动手写了一下最简单的winsock的程序,还是有不少收获。

程序的注释中有详细的介绍各函数的功能和用法,相信对刚入门的童鞋会有帮助。

具体程序见下,服务器端:

// server.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "Winsock2.h"

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

int _tmain(int argc, _TCHAR* argv[])
{
	//这个结构被用来存储被WSAStartup函数调用后返回的Windows Sockets数据
	WSADATA wsaData;   
	WORD    wVersionRequested;  
	int     err,n;
	char    buff[512]={0};

	//MAKEWORD是将两个byte型合并成一个word型,一个在高8位,一个在低8位
	wVersionRequested=MAKEWORD(2,2);

	//为了在应用程序当中调用任何一个Winsock API函数,首先第一件事情就是必须通过WSAStartup函数完成对Winsock服务的初始化,因此需要调用WSAStartup函数
	//wVersionRequested:一个WORD(双字节)型数值,指定了应用程序需要使用的Winsock规范的最高版本。
	//wsaDATA:            指向WSADATA数据结构的指针,用来接收Windows Sockets实现的细节
	err=WSAStartup(wVersionRequested,&wsaData);
	if(err!=0)
		return 0;

	//int socket(int domain, int type, int protocol);
	//socket函数对应于普通文件的打开操作(类似于fopen函数)。普通文件的打开操作返回一个文件描述字,而socket()用于创建一个socket描述符,它唯一标识一个socket。
	//这个socket描述字跟文件描述字一样,后续的操作都有用到它,把它作为参数,通过它来进行一些读写操作。
	//domain:  即协议域,又称为协议族(family)
	//type:     指定socket类型
	//protocol:指定协议
	SOCKET sock=socket(AF_INET,SOCK_STREAM,0);

	//sin_family指代协议族,在socket编程中只能是AF_INET
	//sin_port存储端口号(使用网络字节顺序)
	//sin_addr存储IP地址,使用in_addr这个数据结构
	//htonl将一个32位数从主机字节顺序转换成网络字节顺序
	//htons将机器上的整数转换成“网络字节序”,网络字节序是 big-endian,也就是整数的高位字节存放在内存的低地址处。 
	//而我们常用的 x86 CPU (intel, AMD) 电脑是 little-endian,也就是整数的低位字节放在内存的低字节处。
	SOCKADDR_IN address;
	address.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
	address.sin_family=AF_INET;
	address.sin_port=htons(6000);

	//int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
	//bind()函数把一个地址族中的特定地址赋给socket
	//sockfd:即socket描述字,它是通过socket()函数创建了,唯一标识一个socket
	//addr:一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址
	//addrlen:对应的是地址的长度
	bind(sock,(SOCKADDR*)&address,sizeof(SOCKADDR));

	//如果作为一个服务器,在调用socket()、bind()之后就会调用listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求。
	//listen函数的第一个参数即为要监听的socket描述字
	//第二个参数为相应socket可以排队的最大连接个数
	//socket()函数创建的socket默认是一个主动类型的,listen函数将socket变为被动类型的,等待客户的连接请求。
	listen(sock,5);
	printf("Waiting for client's request......\n");

	SOCKADDR_IN addrClient;
	int len=sizeof(SOCKADDR);
	while(1)
	{
		//accept函数的第一个参数为服务器的socket描述字
		//第二个参数为指向struct sockaddr *的指针,用于返回客户端的协议地址
		//第三个参数为协议地址的长度。如果accpet成功,那么其返回值是由内核自动生成的一个全新的描述字,代表与返回客户的TCP连接
		SOCKET conn=accept(sock,(SOCKADDR*)&addrClient,&len);

		n = recv(conn,buff,512,0);
		buff[n]='\0';
		printf("recv msg from client: %s\n", buff);
		if(strcmp(buff,"close connect")==0)
		{
			closesocket(conn);
			break;
		}
	}
	closesocket(sock);
	return 0;
}
客户端:

// client.cpp : 定义控制台应用程序的入口点。
//

//#pragma comment "ws2_32.lib"
#include "stdafx.h"
#include "Winsock2.h"



int _tmain(int argc, _TCHAR* argv[])
{
	WSADATA wsaData;   
	WORD    wVersionRequested;  
	int     err,n;
	char    buff[512];
	wVersionRequested=MAKEWORD(2,2);
	err=WSAStartup(wVersionRequested,&wsaData);
	if(err!=0)
		return 0;
	SOCKET clientSock=socket(AF_INET,SOCK_STREAM,0);
	SOCKADDR_IN address;
	address.sin_addr.S_un.S_addr=inet_addr("162.105.247.166");
	address.sin_family=AF_INET;
	address.sin_port=htons(6000);
	connect(clientSock,(SOCKADDR*)&address,sizeof(address));

	char recvBuf[100];
	send(clientSock,"close connect",strlen("close connect"),0); 

	closesocket(clientSock);
	WSACleanup();
	return 0;

}
大家单步调试会发现,如果client端进程没有开启,那么server端就会一直停留在accept()函数处,直到client端运行到connect()函数,二者之间才建立连接。

把程序改改,然后让朋友们都装个VS,把client的代码发给他们,咱以后就在console下聊天了,直接把企鹅卸载了,哈哈哈~~~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值