基础的tcp和udp通信 2024.9.3

1、实现TCP的CS模型,即服务器客户端模型。

1.客户端和服务端的socket(),两边分别创建socket套接字。
客户端socket用于创建通信文件标识符,服务端的socket用于监听。

2.之后服务器和客户端都会使用bind函数将套接字绑定指定的端口,用于通信。

3.服务端将一开始的端口用listen绑定用于监听,等待客户端用于处理请求。

4.客户端用connect函数尝试进行tcp连接,发送syn包。服务端用accept回应,开始创建套接字用于处理该客户端请求,进行三次握手后建立tcp连接。

这个服务器accept每建立一个连接,都会建立一个专门处理这个连接的tcp

5.双方就可以用send和revc函数进行通信

6.结束后使用close关闭连接。

值得注意的是:服务器和客户端都需要在通信参数时,需要注意地址族是否相同或者兼容。客户端需要注意目标请求的ip和端口是否一致。

服务器

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

//指定服务器运行的端口
#define PORT 8080
//缓存的大小
#define BUFFER_SIZR 1024
int main(int argc, const char *argv[])
{
    //一个监听请求的套接字,一个用于后续建立tcp请求的套接字
	int server_fd,newserver_fd;
    //用于定义通信协议的参数
	struct sockaddr_in address;
	int addlen=sizeof(address);
	char buffer[BUFFER_SIZR]={0};


    //创建监听套接字
	if((server_fd=socket(AF_INET,SOCK_STREAM,0))==0){
		perror("监听套接字创建失败");
		exit(EXIT_FAILURE);
	}
//设置IPV4协议
	address.sin_family=AF_INET;
//设置为可接收任意接口
	address.sin_addr.s_addr=INADDR_ANY;
//设定服务器运行端口
//htons:将本地运行数据转化成网络数据(与大小端有关)。
	address.sin_port=htons(PORT);

//对套接字进行绑定
	if(bind(server_fd,(struct sockaddr*)&address,sizeof(address))<0){
		perror("绑定失败");
		exit(EXIT_FAILURE);
	}

//开始监听
	if(listen(server_fd,3)<0){
		perror("监听失败");
		exit(EXIT_FAILURE);
	}

//若接收到连接开始创建连接套接字
	if((newserver_fd=accept(server_fd,(struct sockaddr*)&address,(socklen_t*)&addlen))<0){
		perror("创建用户套接字失败");
		exit(EXIT_FAILURE);
	}

	read(newserver_fd,buffer,BUFFER_SIZR);
	printf("接收的数据为%s\n",buffer);

	char str[]="这是服务器回复给你的消息";
	send(newserver_fd,str,strlen(str),0);

	close(server_fd);
	close(newserver_fd);

	return 0;
}

客户端

#include <stdio.h>
#include <string.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <sys/socket.h>
#define PORT 8080
#define BUFFER_SIZE 1024
#define IPADDRESS "127.0.0.1"

int main(int argc, const char *argv[])
{
    //建立连接用的套接字
	int sock=0;
    //建立通信的参数结构体
	struct sockaddr_in serv_addr;
	char buffer[BUFFER_SIZE]={0};
    
    //建立套接字
	if((sock=socket(AF_INET,SOCK_STREAM,0))<0){
		printf("套接字创建失败");
		return -1;
	}

    //设置通信参数
	serv_addr.sin_family=AF_INET;
	serv_addr.sin_port=htons(PORT);
    
    //用于将10.这样的十进制字符串转化成网络二进制
	if(inet_pton(AF_INET,IPADDRESS,&serv_addr.sin_addr)<=0){
		printf("转化失败");
		return -1;
	}
	
    //尝试与服务器建立连接
	if(connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr))<0){
		printf("连接建立失败");
		return -1;
	}
	char str[]="来自客户端的消息";
	send(sock,str,strlen(str),0);

	read(sock,buffer,BUFFER_SIZE);
	printf("客户端回复消息%s\n",buffer);
	
	close(sock);


	return 0;
}

2.UDP服务器中,使用connect函数,实现唯一的客户端与服务器通话。

这边需要注意的是,tcp使用的是字节流因此可以用send和recv函数,而udp使用的是报文,因此发送使用的是sendto和recvfrom进行数据的收发。

服务端

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080
#define BUFFER_SIZE 1024

int main(int argc, const char *argv[]) {
    int sockid = 0;
    char buffer[BUFFER_SIZE];
    struct sockaddr_in seraddr, cliaddr;
    socklen_t cliaddr_len;

    if ((sockid = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("创建套接字失败");
        exit(EXIT_FAILURE);
    }
    memset(&seraddr, 0, sizeof(seraddr));

    seraddr.sin_family = AF_INET;
    seraddr.sin_addr.s_addr = INADDR_ANY;
    seraddr.sin_port = htons(PORT);

    if (bind(sockid, (const struct sockaddr *)&seraddr, sizeof(seraddr)) < 0) {
        perror("绑定失败");
        exit(EXIT_FAILURE);
    }

    // 接收来自客户端的消息
    cliaddr_len = sizeof(cliaddr);
    int n = recvfrom(sockid, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&cliaddr, &cliaddr_len);
    buffer[n] = '\0';
    printf("来自客户端: %s\n", buffer);

    // 发送回复
    sendto(sockid, "来自服务端", strlen("来自服务端"), 0, (const struct sockaddr *)&cliaddr, cliaddr_len);

    close(sockid);
    return 0;
}

客户端

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080
#define BUFFER_SIZE 1024

int main(int argc, const char *argv[]) {
    int sockfd;
    char buffer[BUFFER_SIZE];
    struct sockaddr_in servaddr;

    // 创建UDP套接字
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("套接字创建失败");
        exit(EXIT_FAILURE);
    }

    memset(&servaddr, 0, sizeof(servaddr));

    // 设置服务器地址和端口
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(PORT);
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);

    // 发送消息到服务器
    sendto(sockfd, "来自客户端", strlen("来自客户端"), 0, (const struct sockaddr *)&servaddr, sizeof(servaddr));
    printf("消息已发送。\n");

    // 接收服务器回复
    int n = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, NULL, NULL);
    buffer[n] = '\0';
    printf("来自服务端: %s\n", buffer);

    close(sockfd);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值