windows socket网络编程基础知识

下面介绍网络7层协议在WINDOWS的实现:

7层协议 WIN系统 
________________________________________ 
7 应用层 7 应用程序 
________________________________________________ 
6 表示层 6 WINSOCK API(DLL) 
___________________________________________ 
5 会话层 5 SPI(DLL) 
__________________________________________________ 
4 传输层 4 TDI(VXD,SYS) 
___________________________________________________ 
3 网络层 3 NDIS(VXD,SYS) 
__________________________________________________ 
2 数据链路层 2 网卡驱动程序(VXD,SYS) 
___________________________________________ 
1 物理层 1 网卡 
_________________________________________________ 
相信这个映射图可以让大家比较清楚了解他们的对应关系

TCP协议图示

应用程序协议 HTTP FTP TELNET 
传输协议 TCP UDP 
网际协议 IP 
物理层协议 网卡

IP协议保证数据的传输,TCP协议保证数据传输的质量. 
TCP/IP协议基于四层结构:应用层,传输层,网络层,接口层,数据在传输时每通过一层就要在数据上加个头,其中的数据供接受端同层使用,在 
接收端,每经过一层就把头去掉,来保证传输数据格式的一致.

TCP头部结构: 
16位源端口号 16位目的端口号 
_______________________________________________________________________________ 
32位序列号 
___________________________________________________________________________ 
32位确认号 
_____________________________________________________________________________________ 
4位首部长度+6位保留字 6位标志 16位窗口大小 
_______________________________________________________________________________________ 
16位效验和 16位紧急数据偏移量 
_____________________________________________________________________________________ 
数据段 
_______________________________________________________________________________

IP头部结构: 
4位IP版本号 4位首部长度 8位服务类型 16位总长度 
___________________________________________________________________________________________ 
16位标示 3位标志和偏移 
__________________________________________________________________________ 
8位生存时间 8位协议 16位IP首部效验和 
_________________________________________________________________________________________ 
32位源IP地址 
___________________________________________________________________________________________ 
32位目的IP地址 
________________________________________________________________________________________ 
TCP头和数据

____________________________________________________________________________ 
第四节 关于服务器和客户端编程

在网络编程中,最常用和最基础的就是WINSOCK. 现在我们讨论WINDOWS下的SOCKET编程.

大凡在WIN32平台上的WINSOCK编程都要经过下列步骤: 
定义变量->获得WINDOCK版本->加载WINSOCK库->初始化->创建套接字->设置套接字选项->关闭套接字>卸载WINSOCK库->释放资源

下面介绍WINSOCK C/S的建立过程:

服务器 客户端 
________________________________________________ 
1 初始化WSA 1 初始化WSA 
____________________________________________________ 
2 建立一个SOCKET 2 建立一个SOCKET 
_____________________________________________________ 
3 绑定SOCKET 3 连接到服务器 
_____________________________________________________ 
4 在指定的端口监听 4 发送和接受数据 
_____________________________________________________ 
5 接受一个连接 5 断开连接 
______________________________________________________- 
6 发送和接受数据 
___________________________________________________ 
7 断开连接 
__________________________________________________

大家注意,在VC中进行WINSOCK编程时,需要引入如下两个库文件:WINSOCK.H(这个是WINSOCK API的头文件,WIN2K以上支持WINSOCK2,所以 
可以用WINSOCK2.H);Ws2_32.lib(WINSOCK API连接库文件). 
使用方式如下: 
#include 
#pragma comment(lib,"ws2_32.lib")

大家注意,在VC中进行WINSOCK编程时,需要引入如下两个库文件:WINSOCK.H(这个是WINSOCK API的头文件,WIN2K以上支持WINSOCK2,所以 
可以用WINSOCK2.H);Ws2_32.lib(WINSOCK API连接库文件). 
使用方式如下: 
#include 
#pragma comment(lib,"ws2_32.lib")

下面我们通过具体的代码演示服务器和客户端的工作流程:

首先,建立一个WSADATA结构,通常用wsaData 
WSADATA wsaData;

然后,调用WSAStartup函数,这个函数是连接应用程序与winsock.dll的第一个调用.其中,第一个参数是WINSOCK 版本号,第二个参数是指向 
WSADATA的指针.该函数返回一个INT型值,通过检查这个值来确定初始化是否成功.调用格式如下:WSAStartup(MAKEWORD(2,2),&wsaData),其中 
MAKEWORD(2,2)表示使用WINSOCK2版本.wsaData用来存储系统传回的关于WINSOCK的资料.

if(iResuit=WSAStartup(MAKEWORD(2,2),&wsaData)!=0) 

printf("WSAStartup failed:%d",GetLastError()); //返回值不等与0,说明初始化失败 
ExitProcess(); //退出程序 
}

应用程序在完成对请求的SOCKET库使用后,要调用WSACleanup函数来接触SOCKET库的绑定,并且释放资源.

注意WSAStartup初始化后,必须建立一个SOCKET结构来保存SOCKET句柄.

下面我们建立一个SOCKET.

首先我们建立一个m_socket的SOCKET句柄,接着调用socket()函数,函数返回值保存在m_socket中.我们使用AF_INFE,SOCK_STREAM,IPPROTO_TCP 
三个参数.第一个表示地址族,AF_INFE表示TCP/IP族,第二个表示服务类型,在WINSOCK2中,SOCKET支持以下三种类型;

SOCK_STREAM 流式套接字 
SOCK_DGRAM 数据报套接字 
SOCK_RAW 原始套接字

第三个参数表示协议:

IPPROTO_UDP UDP协议 用于无连接数据报套接字 
IPPROTO_TCP TCP协议 用于流式套接字 
IPPROTO_ICMP ICMP协议用于原始套接字

m_socket=socket(AF_INFE,SOCK_STREAM,IPPROTO_TCP); //创建TCP协议

以下代码用于检查返回值是否有错误:

if(m_scoket==INVALID_SOCKET) 

prinrf("Error at socket():%d\n",GetLastError()); 
WSACleanup(); //释放资源 
return; 

说明,如果socket()调用失败,他将返回INVALID_SOCKET.

为了服务器能接受一个连接,他必须绑定一个网络地址,下面的代码展示如何绑定一个已经初始化的IP和端口的Socket.客户端程序用这个 
IP地址和端口来连接服务器.

sockaddr_in service; 
service.sin_family=AF_INET; //INTERNET地址族 
service.sin_addr.s_addr=inet_addr("127.0.0.1"); //将要绑定的本地IP地址 
service.sin_port=htons(27015); //27015将要绑定的端口

下面我们调用BIND函数,把SOCKET和SOCKADDR以参数的形式传入,并检查错误.

if(bind(m_socket,(SOCKADDR*)&SERVICE,sizeof(service))==SOCKET_ERROR) 

printf("bind() failed.\n"); 
closesocket(m_socket); 
return; 
}

当绑定完成后,服务器必须建立一个监听队列,以接受客户端的请求.listen()使服务器进入监听状态,该函数调用成功返回0,否则返回 
SOCKET_ERROR.代码如下:

if(listen(m_socket,1)==SOCKET-ERROR) 

printf("error listening on socket.\n"); 
}

服务器端调用完LISTEN()后,如果此时客户端调用CONNECT()函数,服务器端必须在调用ACCEPT().这样服务器和客户端才算正式完成通信程序的 
连接动作.

一旦服务器开始监听,我们就要指定一个句柄来表示利用ACCEPT()函数接受的连接,这个句柄是用来发送和接受数据的表示.建立一个SOCKET句柄 
Socket AcceptSocket 然后利用无限循环来检测是否有连接传入.一但有连接请求,ACCEPT()函数就会被调用,并且返回这次连接的句柄.

printf("waitong for a client to connect...\n"); 
while(1) 

AcceptSocket=SOCKET_ERROR; 
while(AcceptSocket==SOCKET_ERROR) 

AcceptSocket=accept(m_socket,NULL,NULL); 

}

下面看客户端端代码:

sockaddr_in clientService; 
clientService.sin_family=AF_INET; //INTERNET地址族 
clientService.sin_addr.s_addr=inet_addr("127.0.0.1"); //将要绑定的本地IP地址 
clientService.sin_port=htons(27015); //27015将要绑定的端口

下面调用CONNECT()函数:

if ( connect( m_socket, (SOCKADDR*) &clientService, sizeof(clientService) ) == SOCKET_ERROR) 

printf( "Failed to connect.\n" ); 
WSACleanup(); 
return; 
} //如果调用失败清理退出 
//调用成功继续读写数据

_____________________________________________________________________________________ 
到这里,服务器和客户端的基本流程介绍完毕,下面我们介绍数据交换.

send(): 
int send 

SOCKET s, //指定发送端套接字 
const char FAR?*buf, //指明一个存放应用程序要发送的数据的缓冲区 
int len, //实际要发送的数据字节数 
int flags //一般设置为0 
}; 
C/S都用SEND函数向TCP连接的另一端发送数据.

recv(): 
int recv 

SOCKET s, //指定发送端套接字 
char FAR?*buf, //指明一个缓冲区 存放RECC受到的数据 
int len, //指明BUF的长度 
int flags //一般设置为0

}; 
C/S都使用RECV函数从TCP连接的另一端接受数据

_______________________________________________________________________________________________

下面将完整的程序代码提供如下,大家可直接编译运行

首先看客户端的代码:

#include<winsock2.h>
#include<stdio.h>
#pragma comment(lib, "ws2_32.lib") 
void main() {

// 初始化 Winsock. 
WSADATA wsaData; 
int iResult = WSAStartup( MAKEWORD(2,2), &wsaData ); 
if ( iResult != NO_ERROR ) 
printf("Error at WSAStartup()\n");

// 建立socket socket. 
SOCKET client; 
client = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );

if ( client == INVALID_SOCKET ) { 
printf( "Error at socket(): %ld\n", WSAGetLastError() ); 
WSACleanup(); 
return; 
}

// 连接到服务器. 
sockaddr_in clientService;

clientService.sin_family = AF_INET; 
clientService.sin_addr.s_addr = inet_addr( "127.0.0.1" ); 
clientService.sin_port = htons( 27015 );

if ( connect( client, (SOCKADDR*) &clientService, sizeof(clientService) ) == SOCKET_ERROR) { 
printf( "Failed to connect.\n" ); 
WSACleanup(); 
return; 
}

// 发送并接收数据. 
int bytesSent; 
int bytesRecv = SOCKET_ERROR; 
char sendbuf[32] = "Client: Sending data."; 
char recvbuf[32] = "";

bytesSent = send( client, sendbuf, strlen(sendbuf), 0 ); 
printf( "Bytes Sent: %ld\n", bytesSent );

while( bytesRecv == SOCKET_ERROR ) { 
bytesRecv = recv( client, recvbuf, 32, 0 ); 
if ( bytesRecv == 0 || bytesRecv == WSAECONNRESET ) { 
printf( "Connection Closed.\n"); 
break; 

if (bytesRecv < 0) 
return; 
printf( "Bytes Recv: %ld\n", bytesRecv ); 
}

return; 
}

下面是服务器端代码:

#include<winsock2.h>
#include<stdio.h> 
#pragma comment(lib, "ws2_32.lib") 
void main() {

// 初始化 
WSADATA wsaData; 
int iResult = WSAStartup( MAKEWORD(2,2), &wsaData ); 
if ( iResult != NO_ERROR ) 
printf("Error at WSAStartup()\n");

// 建立socket 
SOCKET server; 
server = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );

if ( server == INVALID_SOCKET ) { 
printf( "Error at socket(): %ld\n", WSAGetLastError() ); 
WSACleanup(); 
return; 
}

// 绑定socket 
sockaddr_in service;

service.sin_family = AF_INET; 
service.sin_addr.s_addr = inet_addr( "127.0.0.1" ); 
service.sin_port = htons( 27015 );

if ( bind( server, (SOCKADDR*) &service, sizeof(service) ) == SOCKET_ERROR ) { 
printf( "bind() failed.\n" ); 
closesocket(server); 
return; 
}

// 监听 socket 
if ( listen( server, 1 ) == SOCKET_ERROR ) 
printf( "Error listening on socket.\n");

// 接受连接 
SOCKET AcceptSocket;

printf( "Waiting for a client to connect...\n" ); 
while (1) { 
AcceptSocket = SOCKET_ERROR; 
while ( AcceptSocket == SOCKET_ERROR ) { 
AcceptSocket = accept( server, NULL, NULL ); 

printf( "Client Connected.\n"); 
server = AcceptSocket; 
break; 
}

// 发送接受数据 
int bytesSent; 
int bytesRecv = SOCKET_ERROR; 
char sendbuf[32] = "Server: Sending Data."; 
char recvbuf[32] = "";

bytesRecv = recv( server, recvbuf, 32, 0 ); 
printf( "Bytes Recv: %ld\n", bytesRecv );

bytesSent = send( server, sendbuf, strlen(sendbuf), 0 ); 
printf( "Bytes Sent: %ld\n", bytesSent );

return; 

本程序仅仅描述了同步的情况!

第五节 多线程编程介绍

对于多线程的基本概念,我不在赘述,是个只要学习过一门编程语言就应该多进程和线程有个基本的了解.这里重点介绍一下如何实现多线程.

通常一个程序的主线程有操作系统创建,如果想让其创建额外的线程,可以调用CreateThread()函数来完成.函数原形如下:

HANDLE CreateThread() 

LPSECURITY_ATTRIBUTES LPThreadAttributes, //指向SECURITY_ATTRIBUTES的指针 
SIZE_T dwStackSize, //表示线程为自己所用堆栈分配的地址空间的大小 系统缺省值为0 
LPTHREAD_START-TOUTINE lpStartAddress, //表示新线程开始执行时代码所在函数的地址 即线程函数名 
LPVOID lpParameter, //是传入线程函数的参数 
DWORD dwCreationFlags, //指定控制线程创建的附加标志 取0线程立即执行 取CREATE_SUSPENDED线程挂起 
LPDWORD lpThreadld //是个DWORD类型的地址,返回赋给该新线程的ID 
}

线程函数lpParameter必须有以下原形:

DWORD WINAPI XXXThreadFun(LPVOID lpParameter) 

return(0); 
}

________________________________________________________________________________________ 
下面我们来创建一个线程:

#include 
#include 
DWORD WINAPI ThreadFunc( LPVOID lpParam ) //线程函数,跟普通的函数没什么两样 

printf( "Parameter = %d.", *(DWORD*)lpParam ); 
return 0; 
}

VOID main( VOID ) 

DWORD dwThreadId, dwThrdParam = 1; 
HANDLE hThread; 
hThread = CreateThread( NULL,0,ThreadFunc,&dwThrdParam, 0,&dwThreadId); 
if (hThread == NULL) 

printf( "CreateThread failed (%d)\n", GetLastError() ); 

else 

_getch(); 
CloseHandle( hThread ); 

}

关于线程同步的问题,这里就不再讲解,请大家自己查阅资料,不查阅以后可能会有困难啊.培养一下各位的自己动手能力.

时间: 2024-11-18 12:50:43

windows socket网络编程基础知识的相关文章

嵌入式 Linux网络编程(一)——Socket网络编程基础

嵌入式 Linux网络编程一--Socket网络编程基础 一.Socket简介 1.网络中进程间通信 本机进程使用进程号区别不同的进程进程间通信方式有管道.信号.消息队列.共享内存.信号量等.网络中进程间的通信首先需要识别进程所在主机在网络中的唯一标识即网络层的IP地址主机上的进程可以通过传输层的协议与端口号识别. 2.Socket原理 Socket是应用层与TCP/IP协议族通信的中间软件抽象层是一种编程接口.Socket屏蔽了不同网络协议的差异支持面向连接(Transmission Cont

Linux程序设计学习笔记----Socket网络编程基础之TCP/IP协议簇

转载请注明出处: ,谢谢! 内容提要 本节主要学习网络通信基础,主要涉及的内容是: TCP/IP协议簇基础:两个模型 IPv4协议基础:IP地址分类与表示,子网掩码等 IP地址转换:点分十进制\二进制 TCP/IP协议簇基础 OSI模型 我们知道计算机网络之中,有各种各样的设备,那么如何实现这些设备的通信呢? 显然是通过标准的通讯协议,但是,整个网络连接的过程相当复杂,包括硬件.软件数据封包与应用程序的互相链接等等,如果想要写一支将联网全部功能都串连在一块的程序,那么当某个小环节出现问题时,整只

python全栈开发从入门到放弃之socket网络编程基础

网络编程基础 一 客户端/服务器架构 1.硬件C/S架构(打印机) 2.软件C/S架构 互联网中处处是C/S架构 如黄色网站是服务端,你的浏览器是客户端(B/S架构也是C/S架构的一种) 腾讯作为服务端为你提供视频,你得下个腾讯视频客户端才能看它的视频) C/S架构与socket的关系: 我们学习socket就是为了完成C/S架构的开发 为何学习socket一定要先学习互联网协议: 1.首先:本节课程的目标就是教会你如何基于socket编程,来开发一款自己的C/S架构软件 2.其次:C/S架构的

【linux高级程序设计】(第十三章)Linux Socket网络编程基础 2

BSD Socket网络编程API 创建socket对象 int socket (int __domain, int __type, int __protocol) :成功返回socket文件描述符,失败返回-1. 参数1:socket对象使用的地址簇或协议簇  常用的有PF_LOCAL(本机通信).PF_INET(IPv4协议簇).PF_INET6(IPv6协议簇) 参数2:socket的类型.常见有:面向连接的数据流方式:面向无连接的数据报方式 参数3:标识采用哪一种协议,0表示默认. 绑定

【linux高级程序设计】(第十三章)Linux Socket网络编程基础

IP地址定义: struct in_addr{ __u32 s_addr; }; in_addr_t  inet_addr (__const char * __cp) :把点分十进制IP地址字符串转换为32位IP地址(网络存储顺序). in_addr_t inet_network (__const char * __cp) :把点分十进制IP地址字符串转换为32位IP地址(主机字节顺序). char * inet_ntoa (struct in_addr_in) :把32位网络字节顺序的IP地址

【linux高级程序设计】(第十三章)Linux Socket网络编程基础 4

网络调试工具 tcpdump 功能:打印指定网络接口中与布尔表达式匹配的报头信息 关键字: ①类型:host(默认).net.port host 210.27.48.2 //指明是一台主机 net 202.0.0.0 //指明是一个网络 port 23 //指明端口号 ②确认传输方向:src. dst. dst or src. dst and src src 210.27.48.2 //ip包中源地址为此值 dst net 202.0.0.0 //目的网络地址是202.0.0.0 ③协议关键字:

网络编程基础知识

IP:网络中每台主机都必须有一个惟一的IP地址:IP地址是一个逻辑地址:因特网上的IP地址具有全球唯一性:32位,4个字节,常用点分十进制的格式表示,例如192.168.0.200. protocol:为进行网络中的数据交换(通信)而建立的规则.标准或约定(=语义+语法+规则),不同层具有各自不同的协议. poor:在互联网上传输的数据都包含有用来识别目的地的IP地址和端口号.IP地址用来标识网络上的计算机,而端口号用来指明该计算机上的应用程序. TCP:TCP是Transfer Control

linux 网络编程——基础知识

1. 基本知识 (1)socket int socket(int domain, int type, int protocol); domain:确定通信特征,如地址格式 AF(address family) 地址族 AF_INET IPv4因特网域 AF_INET6 IPv6因特网域 AF_UNIX UNIX域 AF_UNSPEC 未指定 type:限定套接字类型,主要设置运输层特征 SOCK_STREAM 有序,可靠,双向面向字节流 SOCK_SEQPACKET 长度固定,有序,面向连接,报

python Socket网络编程 基础

内容概要 Socket介绍 Socket参数介绍 基本Socket实例 Socket实现多连接处理 通过Socket实现简单SSH 通过Socket实现文件传送 1. Socket介绍 Socket Families(地址簇) socket.AF_UNIX unix本机进程间通信  socket.AF_INET IPV4 socket.AF_INET6  IPV6 Socket Types socket.SOCK_STREAM  #for tcp socket.SOCK_DGRAM   #for