宝塔服务器面板,一键全能部署及管理,送你10850元礼包,点我领取

网络编程入门简介套接字技术详细介绍套接字编程所需的函数服务/客户代码

前言

“任何职业都可以成为黑客。 木匠黑客也可以。 没有必要是高科技的。 如果涉及技能,专注于你正在做的事情,就有可能成为黑客。 ”——引自《黑客伦理与信息时代精神》

在这里引入黑客的定义是想提醒自己和大家,他们热衷于分享真正的黑客精神: Open、Free、Share和最新的研究。 时刻牢记黑客精神,如今盛行的“Script Kid”(指只需要使用现成软件进行攻击以获得满足感,从而威胁到网络空间安全的人)。 我希望大家能为网络环境贡献自己的力量。

我是刚开始学习黑客编程的ssdxlz。 在这里做笔记。 错误请向frdpd们指出。

网络编程入门是进入黑客神圣殿堂的第一课,掌握网络编程有助于更好地控制目标计算机。 我个人使用的编程环境是CodeBlocks。 在这里网络编程省略了Netapi编程。 我没有亲自运行,而且只在一个局域网内,所以在真正的网络木马病毒中不常见,所以省略。 转移到套接字编程。 套接字编程中使用的库函数因编译环境而异。 如果使用MINGW进行编译,则使用的头文件为winsock2.h,静态链接库为libws2_32.a。 如果是在CodeBlocks上的话,如下图所示。

如果以后仍需要基于静态或动态链接的操作,可以在此手动添加。 在这里也顺便说一下怎么戴DevC。 首先新建工程,本人比较一下饭菜,暂时只知道这个方法。 下图:

VC的情况下,教科书中记载的方法:

#pragmacomment(lib,’ Ws2_32 ) )但我从未成功过,emmm现在使用编码块。

插座技术建议个人详细介绍原理。 我推荐这个博客。

套接字编程所需的函数WSAStartup函数

int wsa startup (wordwversionrequested,LPWSADATA lpWSAData ); 参数的含义wVersionRequested表示程序请求使用的套接字版本,高字节表示子版本,低字节表示指向主版本lpWSAData的WSADATA的指针,并返回到系统套接字否则,将调用任何后续函数。在调用此函数时,操作系统将根据请求的套接字版本搜索相应的库,并将找到的库绑定到该APP应用程序。 然后,APP应用程序可以调用请求的库中的函数。 如果函数成功执行,则返回0。

WSACleanup函数

int wsacleanup (语音) )。

完成使用请求的套接字库后,APP应用程序将使用此函数解除与套接字库的绑定,并释放正在使用的系统资源。

套接字函数

套接字(intaf、int type、int protocol ) )。

语义af指定APP应用程序使用的通信协议的协议系列,对于TCP/IP协议系列,此参数设置为PF_INET或AF_INET。 两者在Windows上属于同一类型指定套接字类型,刘套接字类型为SOCK_STREAM,数据报套接字类型为sock _ dgram protocol APP应用程序使用的通信协议,TCP为IP协议

其实还有一个WSA套接字函数,这里不介绍。 留一个尾巴。 稍后再提。

closesocket函数

intclosecocket (套接字) )。

每个进程都有一个套接字描述符表,表中的每个套接字描述符都对应于操作系统缓冲区中的套接字数据结构,因此可能有多个套接字描述符指向同一套接字数据结构。 套接字数据结构包含一个字段,用于存储引用该结构的次数。 运行该函数,首先检查引用次数,如果为1,则从表象中删除s,释放相应的套接字数据结构; 如果大于1,则仅清除套接字描述符中s的对应表条目,并将引用次数减少1。

如果执行成功,则返回0,否则返回SOCKET_ERROR。

发送函数

int len (套接字,常数char far * buf,int len,int flags ) )。

语义s发送方的套接字描述符buf指示存储要由APP应用处理发送的数据的缓冲len,并且指示实际发送的数据的字节数flags一般是0。 该函数只要将缓冲器中的数据复制到套接字发送缓冲器的剩馀区域,就对传输不负责,并且数据何时被发送由下层的选择协议确定。

如果发送成功,则返回实际复制到发送缓冲区的字节数;如果复制进程或链接断开,则返回SOCKET_ERROR。

发送到函数

ints endto (套接字,const char * buf,int len,int flags,const struct socketaddr * to,int tolen ) )

参数含义s指定发送端的套接字描述符buf指明一个存放应用进程发送数据的缓冲区len指明实际要发送的数据的字节数flags一般置0to指向目的地址的指针tolento的长度

用于无连接的UDP协议,因为没有事先建立链接,所以需要指定源地址。

recv函数
int recv(SOCKET s, char FAR *buf, int len, int flags) 参数含义s指定接收端的套接字描述符buf指明一个存放应用进程接收数据的缓冲区len指明buf的长度flags一般置0

  与send类似,也是用于面向连接的服务,如果成功则返回实际从接收缓冲区复制的字节数,如果从 socket 的接收队列向 buf 复制的过程中出错则返回SOCKET_ERROR,如果网络连接中断返回0。

recvfrom函数
int recvfrom(SOCKET s, const char * buf, int len, int flags, const struct socketaddr * from,int fromlen) 参数含义s指定接收端的套接字描述符buf指明一个存放应用进程接收数据的缓冲区len指明buf的长度flags一般置0from指向源地址地址的指针fromlenfrom的长度bind函数
int bind(SOCKET s, const struct sockaddr FAR* name, int namelen) 参数含义s指定待绑定的套接字描述符name指明带绑定的IP和端口等信息组合而成的结构体namelen指明name长度// sockaddr 结构体的定义struct sockaddr {u_short sa_family;char sa_data[14];}// 在实际绑定的时候我们通常使用另一个地址结构,用强制类型转换使类型一致struct sockaddr_in {short sin_family;// 指定协议族u_short sin_port;// 指定端口号,一般用htons()函数进行类型转换struct in_addr sin_addr;// 该结构体中的 s_addr 指定要绑定的IP地址//通常用inet_addr()函数对IP地址字符串类型进行转换char sin_zero[8];//} listen函数
int listen(SOCKET s, int backlog) 参数含义s指定待监听的套接字描述符backlog监听队列中最多容纳的客户连接数

执行成功返回0,否则返回SOCKET_ERROR

accept函数
SOCKET accept(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen) 参数含义s指定处于监听状态的套接字描述符addr返回新创建的套接字的地址结构addr新创建的套接字地址结构的长度

  服务程序调用accept函数从处于监听状态的流套接字s的客户请求队列中取出排在最前的一个客户请求,并创建一个新的套接字来与客户套接字创建连接通道,如果连接成功,就返回新创建的套接字描述符,以后与客户端套接字交换数据的是细腻建的套接字;如果失败就返回INVALID_SOCKET。

connect函数
int connect(SOCKET s, const struct sockaddr FAR *name, int namelen) 参数含义s指定客户端套接字描述符name指定服务器地址namelenname的长度

如果连接成功,返回0;否则返回SOCKET_ERROR。

  到这里为止可算是基本把所有会用到的函数都列举出来了,其实更常用的还是 TCP ,列出 UDP 使用的函数也是以防有这方面的需要。还有一个需要注意的地方就是主机字节顺序和网络字节顺序。我们使用的计算机大部分都是小端方式,而网络字节顺序都是大端方式,所以这就涉及到在发送数据时字节顺序的转换。比如上面说到的地址结构中的端口,在赋值的时候,我们使用 htons() 函数进行转换就是为了将我们的整型数字转换为大端方式。还有一个我们所需要的函数就是 inet_addr()。是将一个 IP 地址如“127.1.2.3”转换成一个32整数。如例子,转化完的值为0x0302017f。每两位16进制数代表了 IP 地址中的一位。
  现在前置知识都已经有了,就可以开始编程了,当然推荐的博客里面的程序可以,也可以看一下代码,都是相似的。

服务器/客户 代码

服务器端代码:

#include <stdio.h>#include <winsock2.h>#include <windows.h>unsigned long GetLocalIP() {char szLocalIP[20] = {0};char szHostName[128+1] = “\0”;hostent *phe;if ( gethostname(szHostName, 128) == 0 ) {// Get host addressesphe = gethostbyname(szHostName);for ( int i = 0; phe != NULL && phe->h_addr_list[i] != NULL; i++ ) {sprintf(szLocalIP, “%d.%d.%d.%d”, (UINT)((UCHAR*)phe->h_addr_list[i])[0], (UINT)((UCHAR*)phe->h_addr_list[i])[1], (UINT)((UCHAR*)phe->h_addr_list[i])[2], (UINT)((UCHAR*)phe->h_addr_list[i])[3]);}} elsereturn 0;printf(“host name: %s\nIP: %s\n”, szHostName, szLocalIP);return inet_addr(szLocalIP);}int main() { int sockfd, new_fd;struct sockaddr_in my_addr;struct sockaddr_in their_addr;int sin_size; // 初始化 Windows Socket Dll ,必须放在所有 Socket 编程之前 WSADATA ws; WSAStartup( MAKEWORD(2, 2), // 初始化版本为2.2&ws ); // 返回版本信息 ws 中 GetLocalIP(); sockfd = socket( AF_INET, // 建立 socketSOCK_STREAM, // TCP/IP 协议族0 ); // 套接字类型,通信协议设为0// 绑定本机的830端口my_addr.sin_family = AF_INET; // 协议类型是 INETmy_addr.sin_port = htons(830); // 绑定 830 端口my_addr.sin_addr.s_addr = INADDR_ANY; // 本机任意 IP INADDR_ANYbind(sockfd, // 绑定到 sockfd 上(struct sockaddr*)&my_addr, // 地址结构指针sizeof(struct sockaddr)); // 地址结构大小listen(sockfd, // 在 sockfd 上监听5); // 设定可等待客户队列的大小为5 printf(“listening……\n”); sin_size = sizeof(struct sockaddr_in); new_fd = accept(sockfd,(struct sockaddr*)&their_addr,&sin_size);char their_addr_str[20];sprintf(their_addr_str, “%d.%d.%d.%d”,their_addr.sin_addr.s_addr&0xff,(their_addr.sin_addr.s_addr>>8)&0xff,(their_addr.sin_addr.s_addr>>16)&0xff,(their_addr.sin_addr.s_addr>>24)&0xff);printf(“Connected! Client IP: %s:%d\n”, their_addr_str, their_addr.sin_port);send(new_fd,”ww0830\n”,14,0);printf(“send OK!\n”);closesocket(sockfd);closesocket(new_fd); return 0;}

客户端代码:

#include <stdio.h>#include <winsock2.h>#include <windows.h>#define MAXDATASIZE 100int main(int argc, char* argv[]) { int sockfd, numbytes; char buff[MAXDATASIZE]; struct sockaddr_in their_addr; // 对方的地址端口信息 if ( argc != 2 ) { // 需要有服务端 ip 参数 fprintf(stderr, “usage: client hsotname\n”); exit(1); } WSADATA ws; WSAStartup(MAKEWORD(2, 2), &ws); // 初始化 Windows Socket Dll sockfd = socket(AF_INET, SOCK_STREAM, 0); // 连接对方 their_addr.sin_family = AF_INET; their_addr.sin_port = htons(830); their_addr.sin_addr.s_addr = inet_addr(argv[1]); // 连接服务器端 connect(sockfd, (struct sockaddr*)&their_addr, sizeof(struct sockaddr)); // 接受数据并打印 numbytes = recv(sockfd, buff, MAXDATASIZE, 0); buff[numbytes] = ‘\0’; printf(“Received: %s\n”, buff); closesocket(sockfd); return 0;}