5.win32网络编程(一)
来源:互联网 发布:网络话费卡怎么用 编辑:程序博客网 时间:2024/06/01 07:47
实习完毕,用习惯的mac没了,再回来windows这边的话,估计也是研究的win32网络编程的比较多了。
这篇文章的源代码,是来自之前我做过的一个网安实验——端口复用实验
自我感觉,网络编程都是有那么几个固定步骤的——仿佛套路一般。
这里我是参考了一篇博客的:http://www.cnblogs.com/tianya2543/p/3889495.html
运行环境 : win7下的vc++
具体的解析可以看源代码中的注释:
客户端 client.cpp:
/*---- win32网络编程几步走 (客户端) ------*/ #include <WINSOCK2.H>#include <STDIO.H>#include <iostream>using namespace std;#pragma comment(lib,"ws2_32.lib")int main(int argc, char* argv[]){ WORD sockVersion = MAKEWORD(2,2); WSADATA data; if(WSAStartup(sockVersion, &data) != 0) { return 0; } /* ---- 1、创建套接字(socket) ------ */ SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(sclient == INVALID_SOCKET) { printf("invalid socket !"); return 0; } sockaddr_in serAddr; serAddr.sin_family = AF_INET; serAddr.sin_port = htons(80); serAddr.sin_addr.S_un.S_addr = inet_addr("172.16.0.15"); /* ------- 2、向服务器发出连接请求(connect) ------ */ if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR) {cout<<WSAGetLastError()<<endl; printf("connect error !"); closesocket(sclient); return 0; } char * sendData = "Y好,TCP服务端,我是客户端!\n"; /*------- 3、和服务器端进行通信(send/recv)-------- */ send(sclient, sendData, strlen(sendData), 0); char recData[4096]; int ret = recv(sclient, recData, 4096, 0); if(ret > 0) { recData[ret] = 0x00; printf(recData); } /*------------------- 4、关闭套接字 -------------------*/ closesocket(sclient); WSACleanup(); return 0;}服务端 server.cpp:
/*-- 探寻win32网络编程的套路和步骤 (服务端) -- */ #include<stdio.h>#include<WINSOCK2.H> //加入socket的头文件与链接库#pragma comment(lib,"Ws2_32.lib") //端口复用程序包含监听与连接两种功能的Socketvoid proc(LPVOID d); //工作线程int main(int argc,char * argv[]){WSADATA wsaData;WSAStartup(MAKEWORD(2,2),&wsaData); //socket版本SOCKADDR_IN a,b;//一个是用于外部监听的地址,另一个是接收到accept时用于处理接收的结构a.sin_family=AF_INET; a.sin_addr.s_addr=inet_addr(argv[1]);a.sin_port=htons(80); SOCKET c;/*------------ 1、创建套接字(socket),返回套接字号 ---------*/ c = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); //int socket( int af, int type, int protocol);bool l = TRUE; //这个l有什么用呢?setsockopt(c,SOL_SOCKET,SO_REUSEADDR,(char *)&l,sizeof(l)); //实现端口的重绑定/*------ 2、将套接字绑定到一个本地地址和端口上(bind) ----- */bind(c,(sockaddr *)&a,sizeof(a)); //c和a绑定/*--- 3、将套接字设为监听模式,准备接收客户请求(listen) ---*/listen(c,100); //监听while(1){int x;x = sizeof(b);/* 4、等待客户请求到来;当请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept)*/SOCKET d=accept(c,(sockaddr *)&b,&x); //监听的socket只有一个,而处理接收到的Socket可有多个,个数由连接数决定CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)proc,(LPVOID)d,0,0); //开始处理线程}/*------- 6、返回,等待另一客户请求。 7、关闭套接字 -----*/closesocket(c);return 0;}void proc(LPVOID d){//这个线程的功能是如果鉴定是否是木马程序发送的信息,如果不是就发回给本地的web服务器 SOCKADDR_IN sa; //用于连接web 80端口的Socket结构,sa.sin_family = AF_INET;sa.sin_addr.s_addr=inet_addr("127.0.0.1");sa.sin_port=htons(80);SOCKET web=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);connect(web,(sockaddr *)&sa,sizeof(sa));char buf[4096];SOCKET ss = (SOCKET) d;while(1){/*----- 5、用返回的套接字和客户端进行通信(send/recv) ----*/int n = recv(ss,buf,4096,0);if(n==0) break;if(n > 0 && buf[0] == 'y')//木马特征值为buf[0] == 'y'{send(ss,"hello!,my hacket master!",25,0);}else{send(web,buf,n,0);n=recv(web,buf,4096,0);if(n == 0) break;else send(ss,buf,n,0);}}closesocket(ss);}再看到当记录的笔记:
sockaddr用于存储参与(IP)Windows套接字通信的计算机上的一个internet协议(IP)地址。
为了统一地址结构的表示方法,统一接口函数,使得不同的地址结构可以被bind()、connect()、recvfrom()、sendto()等函数调用。
但一般的编程中并不直接对此数据结构进行操作,而使用另一个与之等价的数据结构sockaddr_in。
struct sockaddr_in { short int sin_family; unsigned short int sin_port; struct in_addr sin_addr; unsigned char sin_zero[8]; }; sin_family:指代协议族,在socket编程中只能是AF_INET, Address family
sin_port:存储端口号(使用网络字节顺序)
sin_addr:存储IP地址,使用in_addr这个数据结构(Internet address)
sin_zero:是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。
Same size as struct sockaddr
而其中in_addr结构的定义如下:
typedef struct in_addr { union { struct{ unsigned char s_b1,s_b2, s_b3,s_b4;} S_un_b;struct{ unsigned short s_w1, s_w2;} S_un_w; unsigned long S_addr; } S_un; } IN_ADDR;阐述下in_addr的含义,很显然它是一个存储ip地址的共用体有三种表达方式:
第一种用四个字节来表示IP地址的四个数字;
第二种用两个双字节来表示IP地址;
第三种用一个长整型来表示IP地址。
给in_addr赋值的一种最简单方法是使用inet_addr函数,它可以把一个代表IP地址的字符串赋值转换为in_addr类型,
如
addrto.sin_addr.s_addr=inet_addr("192.168.0.2");其反函数是inet_ntoa,可以把一个in_addr类型转换为一个字符串。
htons是将整型变量从主机字节顺序转变成网络字节顺序,
就是整数在地址空间存储方式变为:高位字节存放在内存的低地址处。
网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,
从而可以保证数据在不同主机之间传输时能够被正确解释,网络字节顺序采用big-endian排序方式。
所谓big-endian,可以参考博客: http://blog.csdn.net/andkylee/article/details/5361078
重点: 对于跨越多个字节的对象,一般它所占的字节都是连续的,它的地址等于它所占字节最低地址。
网络传输是以字节为单位进行的
但是里面有一段代码,我看了好久也没看懂原理,
#include <stdio.h>#include <assert.h>#include<iostream>using namespace std;int main( void ){ short test; FILE* fp; test = 0x3132; //(31ASIIC码的’1’,32ASIIC码的’2’) cout<<test<<endl; //等于 12594 if ((fp = fopen ("d:/test.txt", "wb")) == NULL) assert(0); cout<<fwrite(&test, sizeof(short), 1, fp)<<endl; //对了,fwrite是一个个字节写进去的! fclose(fp);}后来终于看懂了!首先,ascii的0代表的是空字符,0x31是一个字节,0x32是一个字节
按照大端小端的区别,就是大端12,小端21
阅读全文
0 0
- 5.win32网络编程(一)
- Win32 串口编程(一)
- Win32 串口编程(一)
- Win32 串口编程(一)
- Win32 串口编程(一)
- Win32 网络编程
- Win32 网络编程
- Win32 网络编程
- win32网络编程入门
- win32网络编程【UDP】
- 《win32多线程编程》读后感(一)
- Win32编程心得。一
- Win32 RPC 编程(一)
- Win32多线程编程(一)
- Win32 RPC 编程(一)
- Win32 Windows编程 一
- win32编程学习(一)
- 网络编程(一)
- bat加密及解密方法
- linux程序开机自启动顺序
- Writing A Threadpool in Rus
- Demo_JDBC_实现一个用户登陆的功能并改进sql的注入问题
- 连分数分解法寻找整数的因子(Python)
- 5.win32网络编程(一)
- 文章标题
- 关于RStudio出现中文乱码问题的解决
- REST与RESTFul API最佳实践(转载来自于慕课网)
- 二级Java语言程序设计考试大纲(2013年版)
- 微信公众号广告点击率预估效果优化
- 交叉熵为何能作损失函数
- 25-SpringBoot——核心-Spring Data JPA
- CSU 1811 Tree Intersection(Treap启发式合并)