IP地址和端口
IP地址:在局域网或者互联网中区分不同主机的编号
端口:同一电脑主机内,可能有多重不同的网络通讯软件,一个端口在同一时间内只能给某一个软件的进程使用.
各种不同的软件占用了各自不同的端口之后,数据送达到这台主机后,就会自动按端口进行分理输送.
查看本机IP地址命令:ipconfig
注意在虚拟机中要修改连接的IP地址跟本机不一样
UDP方式发送数据
数据的发送:
#include "stdafx.h"
#include<winsock2.h>
#pragma comment(lib,"Ws2_32.lib")
#define PORT 1111 //绑定的端口
void main()
{
WSADATA wsaData = {0};
if (0 != WSAStartup(0x0202, &wsaData))//加载socket库
{
printf("socket库加载失败\n");
return;
}
//创建套接字
SOCKET sock=socket(AF_INET, //文档建议使用IPV6模式,套接字要有两个版本IPV4和IPV6.
SOCK_DGRAM, //UDP
0 //自动选择协议
);
//绑定端口
sockaddr_in sa = {AF_INET,htons(PORT)}; //发送端可以不绑定端口,系统自动分配,这样就可以启动多个发送端
//这里的绑定没有指明IP地址,表明绑定本机的所有IP地址
if (bind(sock, (sockaddr*)&sa, sizeof(sockaddr_in))!=0)
{
printf("绑定失败\n");
return;
}
sa.sin_port = htons(9000); //发送目标的端口
//htons把主机字节序转换成网络字节序
sa.sin_addr.s_addr = inet_addr("192.168.1.4"); //发送目标的IP地址 本机使用ipconfig命令查找到的网卡信息的IPV4地址
//inet_addr函数把字符串转换成一个4字节的整数型数据
sendto(sock,
"你好", //发送的内容
4, //发送内容的长度
0,
(sockaddr*)&sa, //指定发送的目标IP和端口
sizeof(sockaddr_in)
);
}
数据的接收
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib,"Ws2_32.lib")
#define PORT 9000
void main()
{
WSADATA wsaData = { 0 };
if (0 != WSAStartup(0x0202, &wsaData))//加载socket库
{
printf("socket库加载失败\n");
return;
}
//创建套接字
SOCKET sock = socket(AF_INET, //文档建议使用IPV6模式,套接字要有两个版本IPV4和IPV6.
SOCK_DGRAM, //UDP
0 //自动选择协议
);
//绑定端口 这里就必须绑定端口了 否则发送端找不到发送的对象
SOCKADDR_IN sa = { AF_INET,htons(PORT) };
if (bind(sock, (struct sockaddr*)&sa, sizeof(SOCKADDR_IN)) != 0)
{
printf("绑定失败\n");
return;
}
char buffer[2048] = { 0 };
SOCKADDR_IN from = { 0 };
int len = sizeof(SOCKADDR_IN);
while (TRUE)
{
ULONG recvSize = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&from, &len);
printf("接收到%d字节的数据\n", recvSize);
printf("发送端的IP地址:%s\n", inet_ntoa(from.sin_addr)); //把IP地址转换成字符串
printf("发送端的端口%d\n", htons(from.sin_port)); //把端口由网络字节序转换成主机字节序
}
}
sockaddr和sockaddr_in
sockaddr_in 结构更易于使用,直接指明了端口和IP地址成员,而sockaddr极不好用.
两个结构的大小是一样的,所以都是使用sockaddr_in
TCP
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<winsock2.h>
#include <Windows.h>
#include<stdio.h>
#pragma comment(lib,"Ws2_32.lib")
#define PORT 7063 //服务器的端口
int MyRecv(SOCKET sock, char* Buf, int Len)
{
int r = 0;
while (1 == 1)
{
r = recv(sock, Buf, Len, 0);
if (r == 0)
{
if (WSAGetLastError() == 10053)
{
Sleep(20);
continue;
}
else
{
break;
}
}
else
{
break;
}
}
return r;
}
int MySend(SOCKET sock, char* Buf, int Len)
{
int r = 0;
while (1 == 1)
{
r = send(sock, Buf, Len, 0);
if (r == 0)
{
if (WSAGetLastError() == 10053)
{
Sleep(20);
continue;
}
else
{
break;
}
}
else
{
break;
}
}
return r;
}
//服务端先 接收再发送
DWORD ServerSendProc(PVOID p)
{
SOCKET sockCoon = (SOCKET)p;
DWORD Index = 0;
while (1 == 1)
{
//发送消息只能用send
if (MySend(sockCoon, (char*)&Index, 4) != 4)
{
printf("服务器发送数据失败,error:%d\n", WSAGetLastError());
closesocket(sockCoon);
break;
}
Index++;
Sleep(200);
}
return 0;
}
DWORD ServerRecvProc(PVOID p)
{
SOCKET sockCoon = (SOCKET)p;
DWORD Index = 0;
while (1 == 1)
{
DWORD RecvIndex = 0;
//接收消息
int recvSize = MyRecv(sockCoon, (char*)&RecvIndex, 4);
if (SOCKET_ERROR == recvSize)
{
printf("服务器接收数据失败,error:%d\n", WSAGetLastError());
closesocket(sockCoon);
break;
}
printf("接收到的数据 RecvIndex:%d Index:%d \n", RecvIndex, Index);
if (RecvIndex != Index)
{
printf("错误的数据:%d\n", RecvIndex);
closesocket(sockCoon);
break;
}
Index++;
}
return 0;
}
void Server()
{
WSADATA wsaData = { 0 };
if (0 != WSAStartup(0x0202, &wsaData))//加载socket库
{
printf("socket库加载失败\n");
getchar();
return;
}
//创建套接字
SOCKET sock = socket(AF_INET, //文档建议使用IPV6模式,套接字要有两个版本IPV4和IPV6.
SOCK_STREAM, //TCP
0 //自动选择协议
);
//绑定端口
SOCKADDR_IN sa = { AF_INET, htons(PORT) }; //服务器绑定指定端口,客户端访问这个端口
sa.sin_addr.S_un.S_addr = inet_addr("127.0.0.2");
//这里的绑定没有指明IP地址,表明绑定本机的所有IP地址
if (bind(sock, (const sockaddr*)&sa, sizeof(SOCKADDR_IN)) != 0)
{
printf("绑定失败\n");
WSACleanup();
getchar();
return;
}
if (listen(sock, 5) == SOCKET_ERROR)
{
printf("绑定失败\n");
WSACleanup();
getchar();
return;
}
while (TRUE)
{
//等待接受别人的连接请求
SOCKADDR_IN connObj; //accept成功 conntObj是连接对象的ip地址和端口信息
int len = sizeof(SOCKADDR_IN);
//连接接受后,返回新的连接socket对象
SOCKET sockCoon = accept(sock, (SOCKADDR*)&connObj, &len);
if (sockCoon == INVALID_SOCKET)
{
printf("接受连接出错,错误码:%d\n", GetLastError());
WSACleanup();
getchar();
return;
}
printf("此次连接的客户端IP地址是:%s 端口是:%d\n", inet_ntoa(connObj.sin_addr), htons(connObj.sin_port));
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ServerSendProc, (LPVOID)sockCoon, 0, 0);
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ServerRecvProc, (LPVOID)sockCoon, 0, 0);
}
closesocket(sock);
WSACleanup();
getchar();
}
DWORD ClientSendProc(PVOID p)
{
SOCKET sockCoon = (SOCKET)p;
DWORD Index = 0;
while (1 == 1)
{
if (MySend(sockCoon, (char*)&Index, 4) != 4)
{
printf("客户端发送数据失败,error:%d\n", WSAGetLastError());
closesocket(sockCoon);
break;
}
Index++;
Sleep(500);
}
return 0;
}
DWORD ClientRecvProc(PVOID p)
{
SOCKET sockCoon = (SOCKET)p;
DWORD Index = 0;
while (1 == 1)
{
DWORD RecvIndex = 0;
//接收消息
int recvSize = MyRecv(sockCoon, (char*)&RecvIndex, 4);
if (SOCKET_ERROR == recvSize)
{
printf("客户端接收数据失败,error:%d\n", WSAGetLastError());
closesocket(sockCoon);
break;
}
printf("接收到的数据 RecvIndex:%d Index:%d \n", RecvIndex, Index);
if (RecvIndex != Index)
{
printf("错误的数据:%d\n", RecvIndex);
closesocket(sockCoon);
break;
}
Index++;
}
return 0;
}
int Client()
{
WSADATA wsaData = { 0 };
if (0 != WSAStartup(0x0202, &wsaData))//加载socket库
{
printf("socket库加载失败\n");
return 0;
}
//创建套接字
SOCKET sock = socket(AF_INET, //文档建议使用IPV6模式,套接字要有两个版本IPV4和IPV6.
SOCK_STREAM, //TCP
0 //自动选择协议
);
//TCP客户端可以不用bind,直接连接
//开始连接
SOCKADDR_IN serverAddr = { AF_INET };
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.2");
serverAddr.sin_port = htons(7063);
if (connect(sock, (SOCKADDR*)&serverAddr, sizeof(SOCKADDR)))
{
printf("连接失败\n");
WSACleanup();
return 0;
}
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ClientSendProc, (LPVOID)sock, 0, 0);
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ClientRecvProc, (LPVOID)sock, 0, 0);
getchar();
closesocket(sock);
WSACleanup();
getchar();
return 0;
}
int main()
{
Server();
getchar();
return 0;
}