网络通信——TCP/UDP编程

网络通信

网络通信概述

IP和端口

数据传输三要素:源、目的、长度 (网络传输中使用“IP和端口”表示源或目的)

image-20230611094115079

网络传输两个对象(server、client)

image-20230611094242702

两种传输方式:TCP/UDP

image-20230611094518466

image-20230611094625234

TCP和UDP原理上的区别

image-20230611094844914

TCP/UDP网络通信交互图(1为tcp,2为udp)

image-20230611095006598

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4sCScjaD-1686487349050)(https://vicent-picture-for-typora.oss-cn-beijing.aliyuncs.com/img_for_typora/image-20230611095022756.png)]

网络编程主要函数

socket函数

int socket(int domain, int type, int protocol);

image-20230611095500594

bind函数

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

image-20230611095816172

listen函数

int listen(int sockfd, int backlog);

image-20230611095918099

accept函数

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

image-20230611100117742

connect函数

int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

image-20230611100251241

send函数

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

image-20230611100421836

recv函数

 ssize_t recv(int sockfd, void *buf, size_t len, int flags);

image-20230611100511664

recvfrom函数

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);

image-20230611100615424

sendto函数

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);

image-20230611100715671

image-20230611100733684

TCP编程

server

#include <sys/types.h>	/* See NOTES */
#include <sys/socket.h> //网络编程所需文件
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>

/* socket
 * bind
 * listen
 * accept
 * send/recv
 */

#define SERVER_PORT 8888 // 服务器端口号
#define BACKLOG 10		 // listen函数中最大同时监听连接数

int main(int argc, char **argv)
{
	int iSocketServer;
	int iSocketClient;
	struct sockaddr_in tSocketServerAddr; // 服务器地址结构体
	struct sockaddr_in tSocketClientAddr; // 客户端地址结构体
	int iRet;
	int iAddrLen;

	int iRecvLen;
	unsigned char ucRecvBuf[1000];

	int iClientNum = -1;

	signal(SIGCHLD, SIG_IGN); // 忽略子进程退出信号,避免僵尸进程
	// 1.创建套接字 远程通信,TCP协议,0默认
	// 执行成功返回文件描述符,失败返回-1
	iSocketServer = socket(AF_INET, SOCK_STREAM, 0);
	if (-1 == iSocketServer)
	{
		printf("socket error!\n");
		return -1;
	}

	tSocketServerAddr.sin_family = AF_INET; // 网络通信
	// htons:主机字节序转网络字节序
	tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */
	tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;	 // 表示可以和任何主机通信
	memset(tSocketServerAddr.sin_zero, 0, 8);		 // 填充0

	// 2.绑定本地地址和端口
	iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
	if (-1 == iRet)
	{
		printf("bind error!\n");
		return -1;
	}

	// 3.监听 10个连接
	iRet = listen(iSocketServer, BACKLOG);
	if (-1 == iRet)
	{
		printf("listen error!\n");
		return -1;
	}

	while (1)
	{
		iAddrLen = sizeof(struct sockaddr);
		/* 调用accept函数来等待客户端来连接,客户连接成功返回一个值,连接失败返回-1; */
		iSocketClient = accept(iSocketServer, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
		if (-1 != iSocketClient)
		{
			iClientNum++;
			/* 支持多个客户端连接,每有一个就调用fork(),并创建一个子进程 */
			// inet_ntoa:将网络字节序IP地址转换为点分十进制IP地址
			printf("Get connect from client %d : %s\n", iClientNum, inet_ntoa(tSocketClientAddr.sin_addr));
			if (!fork()) /* 执行到fork()后马上复制一个代码完全一样的子进程*/
			{			 /* 父进程走fork()=0;子进程走fork()!=0; */
						 // fork函数:创建一个子进程,父进程返回子进程ID,子进程返回0 子进程的PID=父进程PID+1
				/*子进程的源码*/
				while (1)
				{
					/* 接受客户端发来的数据并显示出来 */
					iRecvLen = recv(iSocketClient, ucRecvBuf, 999, 0);
					if (iRecvLen <= 0)
					{
						close(iSocketClient); /* 一直接受客户端传来的消息 */ // 关闭客户端套接字
						return -1;
					}
					else
					{
						ucRecvBuf[iRecvLen] = '\0'; /* 接受到的数据以'\0'结尾 */
						printf("Get Msg From Client %d: %s\n", iClientNum, ucRecvBuf);
					}
				}
			}
		}
	}
	close(iSocketServer); // 关闭服务器套接字
	return 0;
}

client

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>

/* socket
 * connect
 * send/recv
 */

#define SERVER_PORT 8888

int main(int argc, char **argv)
{
	int iSocketClient;
	struct sockaddr_in tSocketServerAddr;

	int iRet;
	unsigned char ucSendBuf[1000];
	int iSendLen;

	if (argc != 2)
	{
		printf("Usage:\n");
		printf("%s <server_ip>\n", argv[0]);
		return -1;
	}

	// 1.创建套接字
	iSocketClient = socket(AF_INET, SOCK_STREAM, 0); // 远程通信,TCP协议,0默认

	tSocketServerAddr.sin_family = AF_INET;
	tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */
	// tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
	if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr))
	{
		printf("invalid server_ip\n");
		return -1;
	}
	memset(tSocketServerAddr.sin_zero, 0, 8);

	// 2.发送连接请求连接服务器
	iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
	if (-1 == iRet)
	{
		printf("connect error!\n");
		return -1;
	}

	while (1)
	{
		if (fgets(ucSendBuf, 999, stdin))
		{
			// 3.发送数据
			iSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0);
			if (iSendLen <= 0)
			{
				// 4.关闭套接字
				close(iSocketClient);
				return -1;
			}
		}
	}

	return 0;
}

执行过程:在linux下先编译两个程序,然后执行server再打开新终端执行client,执行需要输入ip地址,此时在客户端发送字符串,服务器端可以接收到字符串

UDP编程

server

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>

/* socket
 * bind
 * sendto/recvfrom
 */

#define SERVER_PORT 8888

int main(int argc, char **argv)
{
	int iSocketServer;
	int iSocketClient;
	struct sockaddr_in tSocketServerAddr;
	struct sockaddr_in tSocketClientAddr;
	int iRet;
	int iAddrLen;

	int iRecvLen;
	unsigned char ucRecvBuf[1000];

	int iClientNum = -1;

	// 1.创建socket套接字
	iSocketServer = socket(AF_INET, SOCK_DGRAM, 0);
	if (-1 == iSocketServer)
	{
		printf("socket error!\n");
		return -1;
	}

	tSocketServerAddr.sin_family = AF_INET;
	tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */
	tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
	memset(tSocketServerAddr.sin_zero, 0, 8);

	// 2.绑定本地ip地址和端口号
	iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
	if (-1 == iRet)
	{
		printf("bind error!\n");
		return -1;
	}

	while (1)
	{
		iAddrLen = sizeof(struct sockaddr);
		// 3.接收数据 recvfrom常用于无连接的udp通信
		iRecvLen = recvfrom(iSocketServer, ucRecvBuf, 999, 0, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);
		if (iRecvLen > 0)
		{
			ucRecvBuf[iRecvLen] = '\0';
			printf("Get Msg From %s : %s\n", inet_ntoa(tSocketClientAddr.sin_addr), ucRecvBuf);
		}
	}
	// 4.关闭socket套接字
	close(iSocketServer);
	return 0;
}

client

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>

/* socket
 * connect
 * send/recv
 */

#define SERVER_PORT 8888

int main(int argc, char **argv)
{
	int iSocketClient;
	struct sockaddr_in tSocketServerAddr;

	int iRet;
	unsigned char ucSendBuf[1000];
	int iSendLen;

	if (argc != 2)
	{
		printf("Usage:\n");
		printf("%s <server_ip>\n", argv[0]);
		return -1;
	}
	// 1.创建socket套接字
	iSocketClient = socket(AF_INET, SOCK_DGRAM, 0);

	tSocketServerAddr.sin_family = AF_INET;
	tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */
	// tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;
	if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr))
	{
		printf("invalid server_ip\n");
		return -1;
	}
	memset(tSocketServerAddr.sin_zero, 0, 8);

	// 2.连接服务器
	iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));
	if (-1 == iRet)
	{
		printf("connect error!\n");
		return -1;
	}

	while (1)
	{
		if (fgets(ucSendBuf, 999, stdin))
		{
			// 3.发送数据
			iSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0);
			if (iSendLen <= 0)
			{
				// 4.关闭套接字
				close(iSocketClient);
				return -1;
			}
		}
	}

	return 0;
}

总结:TCP和UPD编程的区别

TCPUDP
clientsocket->connect->send/recvsocket->connect->send/recv(可以直接使用sendto,去掉connect)
serversocket->bind->listen->accept->send/recvsocket->bind->sendto/recvfrom
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值