近期的一些小总结(关于TCP/IP协议相关的)

1、基本概念

首先还是记录一下是什么,这个是关于通信的,本地进行消息传递的方式有很多,例如管道,消息队列,共享内存等,都是比较经典的进程间通信的方式,但这都是一个设备之间的进程进行通信,要实现设备和设备之间的通信需要使用Socket来实现。

Socket将网络通信的三元组(ip地址,协议,端口)进行封装,使得进行网络中的进程间通信变得很方便。Socket的通信数据传输方式有两种比较常用的,分别是SOCK_STREAM和SOCK_DGRAM,前面一种是面向连接的数据传输方式,对数据的可靠性要求较高,类似MQTT协议中需要服务质量为1(QOS=1)的情况,第二种则是一种无连接的数据传输方式,设备只会发送数据不做数据校验,不会去管接收方有没有收到数据。(但是这样同样也提高了数据传输的效率

2、建立连接的过程

Socket是基于TCP/IP协议的,这里的TCP/IP是指[TCP(传输控制协议)和IP(网际协议)],可以直接理解为一套网络通信的标准协议格式。对于SOCKET开发者,TCP创建过程和连接拆除过程是由TCP/IP协议栈自动创建的。因此开发者并不需要控制这个过程。

但是可以稍微有一个概念性的了解,例如下面的TCP建立连接时候的三次握手和断开连接的四次挥手:

三次挥手

理解为:

  • A->B:想与B建立连接
  • B->A:同意建立连接
  • A->B:收到

之后就是AB之间进行数据的收发了,连接已经建立好了。

四次握手

理解为:

  • A->B:想断开连接
  • B->A:等待处理一下
  • B->A:好了,可以断开连接
  • A->B:收到

之后就是断开连接,关闭Socket不在进行互相通信了。

3、Socket常用接口

Socket常用接口可以表示为下图所示:(下面的两种分别对应上述的两种常见的Socket接口

TCP_Socket:
在这里插入图片描述
UDP_Socket
在这里插入图片描述

4、示例程序

上述过程的示例程序可以表现为:

tcp_server.c

#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
 
#define PORT 12345		//端口号
#define BACKLOG 5	//最大监听数
 
int main()
{
    
    
	int iSocketFD = 0;  //socket句柄
	int iRecvLen = 0;   //接收成功后的返回值
	int new_fd = 0; 	//建立连接后的句柄
	char buf[4096] = {
    
    0}; //
	struct sockaddr_in stLocalAddr = {
    
    0}; //本地地址信息结构图,下面有具体的属性赋值
	struct sockaddr_in stRemoteAddr = {
    
    0}; //对方地址信息
	socklen_t socklen = 0;  	
 
	iSocketFD = socket(AF_INET, SOCK_STREAM, 0); //建立socket
	if(0 > iSocketFD)
	{
    
    
		printf("创建socket失败!\n");
		return 0;
	}	
 
	stLocalAddr.sin_family = AF_INET;  /*该属性表示接收本机或其他机器传输*/
	stLocalAddr.sin_port = htons(PORT); /*端口号*/
	stLocalAddr.sin_addr.s_addr=htonl("192.168.109.129"); /*IP,括号内容表示本机IP*/
 
	//绑定地址结构体和socket
	if(0 > bind(iSocketFD, (void *)&stLocalAddr, sizeof(stLocalAddr)))
	{
    
    
		printf("绑定失败!\n");
		return 0;
	}
 
	//开启监听 ,第二个参数是最大监听数
	if(0 > listen(iSocketFD, BACKLOG))
	{
    
    
		printf("监听失败!\n");
		return 0;
	}
 
	printf("iSocketFD: %d\n", iSocketFD);	
	//在这里阻塞知道接收到消息,参数分别是socket句柄,接收到的地址信息以及大小 
	new_fd = accept(iSocketFD, (void *)&stRemoteAddr, &socklen);
	if(0 > new_fd)
	{
    
    
		printf("接收失败!\n");
		return 0;
	}else{
    
    
		printf("接收成功!\n");
		//发送内容,参数分别是连接句柄,内容,大小,其他信息(设为0即可) 
		send(new_fd, "这是服务器接收成功后发回的信息!", sizeof("这是服务器接收成功后发回的信息!"), 0);
	}
 
	printf("new_fd: %d\n", new_fd);	
	iRecvLen = recv(new_fd, buf, sizeof(buf), 0);	
	if(0 >= iRecvLen)    //对端关闭连接 返回0
	{
    
    	
		printf("接收失败或者对端关闭连接!\n");
	}else{
    
    
		printf("buf: %s\n", buf);
	}
 
	close(new_fd);
	close(iSocketFD);
 
	return 0;
}

tcp_client.c

#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>

#define PORT 12345			   //目标地址端口号
#define ADDR "192.168.109.129" //目标地址IP

int main()
{
    
    
	int iSocketFD = 0; // socket句柄
	unsigned int iRemoteAddr = 0;
	struct sockaddr_in stRemoteAddr = {
    
    0}; //对端,即目标地址信息
	socklen_t socklen = 0;
	char buf[4096] = {
    
    0}; //存储接收到的数据

	iSocketFD = socket(AF_INET, SOCK_STREAM, 0); //建立socket
	if (0 > iSocketFD)
	{
    
    
		printf("创建socket失败!\n");
		return 0;
	}
	stRemoteAddr.sin_family = AF_INET;
	stRemoteAddr.sin_port = htons(PORT);
	inet_pton(AF_INET, ADDR, &iRemoteAddr);
	stRemoteAddr.sin_addr.s_addr = iRemoteAddr;
	//连接方法: 传入句柄,目标地址,和大小
	if (0 > connect(iSocketFD, (void *)&stRemoteAddr, sizeof(stRemoteAddr)))
	{
    
    
		printf("连接失败!\n");
	}
	else
	{
    
    
		printf("连接成功!\n");
		recv(iSocketFD, buf, sizeof(buf), 0); //将接收数据打入buf,参数分别是句柄,储存处,最大长度,其他信息(设为0即可)。
		printf("Received:%s\n", buf);
	}
	close(iSocketFD); //关闭socket
	return 0;
}

如果建立一个UDP连接的话:

udp_client.c

#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
#include<arpa/inet.h>
 
int main()
{
    
    
     //创建socket对象
     int sockfd=socket(AF_INET,SOCK_DGRAM,0);
 
     //创建网络通信对象
     struct sockaddr_in addr;
     addr.sin_family =AF_INET;
     addr.sin_port =htons(1324);
     addr.sin_addr.s_addr = inet_addr("192.168.109.129"); //IP根据server所在主机的IP设定,这里是运行在同一PC端 
 
     while(1)
     {
    
    
         printf("input:");
         char buf[50];
         char buf1 = 0;
         scanf("%s",&buf);
         sendto(sockfd,&buf,sizeof(buf),0,(struct sockaddr*)&addr,sizeof(addr));
 
         socklen_t len=sizeof(addr);
         recvfrom(sockfd,&buf1,sizeof(buf1),0,(struct sockaddr*)&addr,&len);
 
         if(11 ==buf1)
         {
    
    
            printf(" server 成功接受\n");
         }
         else
         {
    
    
             printf("server 数据丢失\n");
         }
 
     }
     close(sockfd); 
}

udp_server.c

#include<stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int main()
{
    
    
    //创建socket对象
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    //创建网络通信对象
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(1324);
    addr.sin_addr.s_addr = inet_addr("192.168.109.129");

    //绑定socket对象与通信链接
    int ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
    if (0 > ret)
    {
    
    
        printf("bind\n");
        return -1;
    }
    struct sockaddr_in cli;
    socklen_t len = sizeof(cli);

    while (1)
    {
    
    
        char buf[50];
        char buf1;
        recvfrom(sockfd, &buf, sizeof(buf), 0, (struct sockaddr *)&cli, &len);
        printf("recv num =%s\n", buf);

        buf1 = 11;
        sendto(sockfd, &buf1, sizeof(buf1), 0, (struct sockaddr *)&cli, len);
    }
    close(sockfd);
}

使用的makefile

SOURCE = $(wildcard *.c)
TARGETS = $(patsubst %.c, %, $(SOURCE))

CC = gcc
CFLAGS = -Wall -g -lm#如果有math.h要加上这个lm选项

all:$(TARGETS)

$(TARGETS):%:%.c
		$(CC) $< $(CFLAGS) -o $@

.PHONY:clean all
clean:
	-rm -rf $(TARGETS)

参考:
https://www.jianshu.com/p/066d99da7cbd
https://www.cnblogs.com/hissia/p/5730135.html
https://blog.csdn.net/lzl980111/article/details/106188393

猜你喜欢

转载自blog.csdn.net/m0_51220742/article/details/126711517