TCP/IP基础知识

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值