Windows Socket的UDP和TCP编程介绍

时间:2022-12-06 19:01:21

1:网络中进程之间如何通信

  为了实现进程之间通信,首要解决的问题是如何唯一标识一个进程,在本地可以通过进程PID来唯一标识一个进程,但是在网络中则是行不通的,其实TCP/IP协议族已经帮我们解决了这个问题,网络层的"ip 地址"可以唯一标识网络中的主机,而"传输层的 协议+端口"可以唯一标识主机中的应用程序(进程)。这样利用(ip地址,谢谢,端口)就可以标识网络中的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。而现在几乎所有网络应用程序都是采用socket来通信的,那么什么是socket呢?

2:套接字(socket)

  socket起源于Unix,而Unix/Linux基本哲学之一就是"一切皆文件",都可以用"打开Open -> 读写write/read ->关闭close"模式来操作,socket就是该模式的一个实现,socket就是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭),说白了Socket就是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。socket把复杂的TCP/IP协议族隐藏在socket接口后面,对用户来说就是一组简单的接口。让socket去组织数据,以符合指定的协议。

  随着Unix的应用推广,套接字有被引进了windows等操作系统,套接字通常只与同一区域的套接字交换数据,windows只支持一个通信区域,网际域(AF_INET),这个域被使用网际协议簇的通信进程。

3:客户机/服务器模式

  在TCP/IP网络应用中,通信的两个进程间相互作用的主要模式是客户机/服务器模式(client/server),即客户向服务器提出请求,服务器接受到请求后提出相应的服务。

服务器:

 (1):首先服务器先要启动,打开一个通信通道并告知本机,它愿意在某一个地址和端口上接收客户请求。

 (2):等待客户请求到达该端口。

 (3):接收服务请求,处理该客户请求,服务完成后,关闭此进程与客户的通信链路,并终止。

 (4):返回第二步,等待另一个客户请求

 (5):关闭服务器

客户方:

 (1):打开一个通信通道,并连接到服务器所在的主机特定的端口。

 (2):向服务器发送请求,等待并接收应答,继续提出请求。

 (3):请求结束后关闭通信信道并终止

4:基于TCP(面向连接)的socket编程

  Windows Socket的UDP和TCP编程介绍

服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listlen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了,客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

5:基于UDP(面向无连接)的socket编程

  Windows Socket的UDP和TCP编程介绍

服务器先创建socket,将socket绑定(bind)一个本地地址和端口上,等待数据传输(recvfrom).这个时候如果有个客户端创建socket,并且向服务器发送数据(sendto),服务器就建立了连接,实现了数据的通信,连接结束后关闭连接.

6:UDP例子

  Server端

 //注:需要在stdafx.h 里面添加 #pragma comment(lib, "ws2_32.lib")
#include"stdafx.h"
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <windows.h>
using namespace std; #pragma comment(lib, "ws2_32.lib") //add ws2_32.lib int main()
{
WORD wVersionRequested;
WSADATA wsaData;
int err; wVersionRequested = MAKEWORD(, ); err = WSAStartup(wVersionRequested, &wsaData);
if (err != )
{
printf("WSAStartup failed with error: %d\n", err);
return ;
} if (LOBYTE(wsaData.wVersion) != || HIBYTE(wsaData.wVersion) != )
{
printf("Could not find a usable version of Winsock.dll\n");
WSACleanup();
return ;
}
else
{
printf("The Winsock 2.2 dll was found okay\n");
} SOCKET sockSrv = socket(AF_INET,SOCK_DGRAM, ); //创建一个socket句柄;
if( sockSrv == INVALID_SOCKET )
{
printf("socket() fail:%d\n",WSAGetLastError());
return -;
} SOCKADDR_IN addrServ;
memset(&addrServ,,sizeof(addrServ));
addrServ.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrServ.sin_family = AF_INET;
addrServ.sin_port = htons(); //从"主机字节顺序" 转变为 "网络字节顺序" err = bind(sockSrv,(SOCKADDR*)&addrServ,sizeof(SOCKADDR)); //把socket 绑定到指定地址上
if( err != )
{
printf("bind()fail:%d\n",WSAGetLastError());
return -;
} SOCKADDR_IN addrClient;
memset(&addrClient,,sizeof(addrClient)); //在设置每个地址成员之前,整个addr结构应该被初始化0;
int length = sizeof(SOCKADDR);
char recvBuf[];
printf("waiting for client connect!!!!\n");
recvfrom(sockSrv,recvBuf,,,(SOCKADDR*)&addrClient,&length); printf("recvfrom client:: %s\n",recvBuf); closesocket(sockSrv); WSACleanup(); system("PAUSE");
return ;
}

Client端

 // 注:需要在stdafx.h 里面添加 #pragma comment(lib, "ws2_32.lib")
//
#include"stdafx.h"
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <windows.h>
using namespace std; #pragma comment(lib, "ws2_32.lib") //add ws2_32.lib int main()
{
WORD wVersionRequested;
WSADATA wsaData;
int err; wVersionRequested = MAKEWORD(, ); err = WSAStartup(wVersionRequested, &wsaData);
if (err != )
{
printf("WSAStartup failed with error: %d\n", err);
return ;
} if (LOBYTE(wsaData.wVersion) != || HIBYTE(wsaData.wVersion) != )
{
printf("Could not find a usable version of Winsock.dll\n");
WSACleanup();
return ;
}
else
{
printf("The Winsock 2.2 dll was found okay\n");
} SOCKET sockClient = socket(AF_INET,SOCK_DGRAM, ); SOCKADDR_IN addrServ;
memset(&addrServ,,sizeof(addrServ));
addrServ.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
addrServ.sin_family = AF_INET;
addrServ.sin_port = htons();
printf("begin to send data to server::Hello\n");
sendto(sockClient,"Hello\n",strlen("Hello\n")+,,(SOCKADDR*)&addrServ,sizeof(SOCKADDR)); closesocket(sockClient); system("PAUSE");
WSACleanup(); return ;
}

输出的结果为:
Windows Socket的UDP和TCP编程介绍

 7:TCP例子

Server端

 #include"stdafx.h"
#include <winsock2.h>
#include <iostream> #include <string.h>
using namespace std; #pragma comment(lib, "ws2_32.lib") //add ws2_32.lib const int DEFAULT_PORT = ;
int main(int argc,char* argv[])
{ WORD wVersionRequested;
WSADATA wsaData;
int err,iLen;
wVersionRequested = MAKEWORD(,); err = WSAStartup(wVersionRequested,&wsaData);
if( err!= )
{
printf("WSAStartup failed with error: %d\n", err);
return -;
}
if ( LOBYTE(wsaData.wVersion) != || HIBYTE(wsaData.wVersion) != )
{
printf("Could not find a usable version of Winsock.dll\n");
WSACleanup();
return ;
}
else
{
printf("The Winsock 2.2 dll was found okay\n");
} SOCKET sockSrv = socket(AF_INET,SOCK_STREAM,);
if( sockSrv == INVALID_SOCKET )
{
printf("socket() fail:%d\n",WSAGetLastError());
return -;
} SOCKADDR_IN addrSrv;
memset(&addrSrv,,sizeof(addrSrv));
addrSrv.sin_family = AF_INET;
addrSrv.sin_addr.s_addr = htonl(INADDR_ANY);
addrSrv.sin_port = htons(DEFAULT_PORT); err = bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
if( err != )
{
printf("bind()fail:%d\n",WSAGetLastError());
return -;
} err = listen( sockSrv, );//listen函数的第一个参数即为要监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数
if( err != )
{
printf("listen()fail:%d\n",WSAGetLastError());
return -;
}
printf("Server waitting...!!!!!\n");
SOCKADDR_IN addrClt;
int len = sizeof(SOCKADDR);
memset(&addrClt,,len); while()
{
SOCKET sockConn = accept(sockSrv,(SOCKADDR*)&addrClt,&len);
char sendBuf[],hostname[];
if( gethostname(hostname,) != )
{
strcpy_s(hostname,strlen("None")+,"None");
}
sprintf_s(sendBuf,sizeof(sendBuf),"Welecome %s connected to %s!",inet_ntoa(addrClt.sin_addr),hostname); err = send(sockConn,sendBuf,strlen(sendBuf)+,); char recvBuf[]="\0";
iLen = recv(sockConn,recvBuf,,); recvBuf[iLen]='\0';
printf(recvBuf); closesocket(sockConn);
} closesocket(sockSrv); WSACleanup();
return ;
}

Client端

 // client.cpp : 定义控制台应用程序的入口点。
//
#include"stdafx.h"
#include <winsock2.h>
#include <iostream> #include <string.h>
using namespace std; #pragma comment(lib, "ws2_32.lib") const int DEFAULT_PORT = ;
int main(int argc,char* argv[])
{ WORD wVersionRequested;
WSADATA wsaData;
int err,iLen;
wVersionRequested = MAKEWORD(,); err = WSAStartup(wVersionRequested,&wsaData); //load win socket
if( err != )
{
printf("WSAStartup failed with error: %d\n", err);
return -;
} SOCKET sockClt = socket(AF_INET,SOCK_STREAM,);
if( sockClt == INVALID_SOCKET )
{
printf("socket() fail:%d\n",WSAGetLastError());
return -;
} SOCKADDR_IN addrSrv;
memset(&addrSrv,,sizeof(addrSrv));
addrSrv.sin_family = AF_INET;
addrSrv.sin_addr.s_addr = inet_addr("127.0.0.1");
addrSrv.sin_port = htons(DEFAULT_PORT); err = connect(sockClt,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)); if(err ==INVALID_SOCKET)
{
printf("connect()fail:%d\n",WSAGetLastError());
return -;
} char sendBuf[],hostname[];
if( gethostname(hostname,) != ) //如果没有错误的时候gethostname会返回0;
{
strcpy_s(hostname,strlen("None")+,"None");
}
strcpy_s(sendBuf,strlen(hostname)+,hostname);
strcat_s(sendBuf,sizeof(sendBuf)," have connected to you!");
err = send(sockClt,sendBuf,strlen(sendBuf)+,); char recvBuf[]="\0";
iLen = recv(sockClt,recvBuf,,); if( iLen == )
{
return -;
}
else if( iLen == SOCKET_ERROR )
{
printf("recv() fail:%d\n",WSAGetLastError());
return -;
}
else
{
recvBuf[iLen] = '\0';
printf(recvBuf);
printf("\n");
}
closesocket(sockClt); WSACleanup();
system("PAUSE");
return ;
}

输出的结果为
Windows Socket的UDP和TCP编程介绍