D2 - TCP编程

下面是测试

  • | 如何获取一个socket描述符
  • | 如何将socket描述符与电脑IP绑定
  • | 如何监听
  • | 服务器如何连接
  • | 连通后如何读写数据
  • | 客户端如何连接
  • | 整个TCP的流程是怎么样的

第一节

  • socket描述符就是文件描述符,都是一个int整数,有着身份证的作用

1.1 socket函数

int socket(int domain, int type, int protocol);
功能:设置socket通讯的IP域与端口通信方式后,分配一个socket通信的socket描述符
参数1:domin(域)<==>填写IP域是属于IPv4 / IPv6 / 本地IP
AP_INET=PIv4
AF_INET6=IPv6
AF_LOCAL=本地IP
参数2:type<==>socket的端口通信方式选择

SOCK_STEAM=TCP通信的流式套接字
SOCK_DGRAM=UDP通信的数据报套接字
SOCK_RAW=原始套接字
参数3:protocol(协议)<==>UDP与TCP编程时写0,原始套接字编程时填充
返回值:成功->socket描述符 ; 失败->EOF

1.2 bind函数

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能: 将socket网络地址与socket描述符绑定关联
参数1:sockfd <==> socket获取的socket描述符
参数2:sockaddr网络地址结构体变量的地址(IPv4,IPv6,本地网络的网络地址结构体都是不一样的)
ipv4网络地址结构体如下(man 7 ip 可查看)
:在这里插入图片描述
参数3:socket网络地址结构体的长度
返回值:
On success, zero is returned.
On error, -1 is returned,

1.3 listen函数

  • listen(倾听)
int listen(int sockfd, int backlog);
功能:l因为服务器是被动连接,套接字默认是主动的,所以使用isten()将socket主动套接字转化为被动套接字,让服务器进入监听状态
参数1:socket函数获取的socket描述符
参数2" 最大允许几个客户端进行连接
返回值: On success, zero is returned. On error, -1 is returned

1.4 accept函数

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能: 一直等待客户端连接
参数1:服务器的socket描述符
参数2:客户端套接字网络地址
参数3: 参数2的字节长度
返回值: On success, these system calls return a nonnegative integer that is a descriptor for the accepted socket. On error, -1 is returned
(成功:如果与客户端连接成功,就返回一个新的newfd,用来临时通信,失败的话:-1)

1.5 read / write / close 参考前面的文章

  • 由于socket网络描述符就是文件描述符,所以在accept连接成功后,直接使用read / write / close 函数即可accept返回的操作临时文件描述符newfd

1.6 客户端连接函数connet

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能:连接服务器
参数1:客户端的socket描述符
参数2:用于接收客户端的socket网络地址结构体
参数3:用于接收参数2的字节长度
返回值: If the connection or binding succeeds, zero is returned. On error, -1 is returned
服务器ser.c / 客户端cli.c

实现C/S通信

/*===============================================================
*   Copyright (C) 2020 All rights reserved.
*   
*   文件名称:ser.c
*   创 建 者:liujing
*   创建日期:2020年07月24日
*   描    述:
*
*   更新日志:
*
================================================================*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */

void main()
{
	//1:获取socket描述符
	int socketid;
	//AF_INET=IPv4
	//SOCK_STREAM=socket流
	//0=协议默认
	socketid = socket(AF_INET,SOCK_STREAM,0);

	if(socketid!=EOF)
	{
		printf("\n获取ID成功\n");
	}
	else
	{
		perror("\n获取ID失败\n");
	}

	//2:socket网络地址绑定socket描述符
	//socket网络地址赋值 --> For AF_INET see ip(7)
	struct sockaddr_in sockaddr;
	sockaddr.sin_family = AF_INET;
	sockaddr.sin_port = 5001; //5000~65535是用户段口号
	//将点分十进制的IP地址转化为32位地址,存储在sockaddr.sin_addr
	
	if(1 == inet_pton(AF_INET,"192.168.43.70",(void*)&sockaddr.sin_addr))
	{
		printf("\n转换IP-->32位成功\n");
	}
	else
	{
		perror("\n转化IP-->位失败\n");
	}

	//socket描述符绑定网络地址
	if(bind(socketid,(struct sockaddr*)&sockaddr,sizeof(sockaddr)) == EOF)
	{
		perror("\nbind function error\n");
	}
	else
	{
		printf("\nbind function success\n");
	}

	//将网络套接字转化为被动套接字,进入监听状态
	if(0 == listen(socketid,5))
	{
		printf("\n listen function success\n");
	}
	else
	{
		perror("\nlisten function error:\n");
	}

	//等待客户端请求连接
	
	struct sockaddr_in cliaddr;
	int clilen = 0;
	
	int newid = -1;
	printf("\n阻塞等待接入\n");
	newid = accept(socketid,(struct sockaddr*)&cliaddr,&clilen);
	if(newid == -1)
	{
		perror("\naccept function error\n");
	}
	else
	{
		printf("\naccept function success\n");
	}

	//read / write 读取操作文件描述服
	char buf[32];
	char sendbuf[32] = "HELLO WORD";
	int ret;
	while(1)
	{
		ret = read(newid,buf,32);
		write(newid,sendbuf,32);
		puts(buf);

		sleep(1);
		if(ret == 0) //当read / write函数返回0,说明客户端退出,socket连接断开
		{
			printf("\nbreak\n");
			break;  //退出循环
		}
	}
	close(newid);

	close(socketid);
	printf("\nend\n");
}

/*===============================================================
*   Copyright (C) 2020 All rights reserved.
*   
*   文件名称:cli.c
*   创 建 者:liujing
*   创建日期:2020年07月25日
*   描    述:
*
*   更新日志:
*
================================================================*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
void main()
{
	//1.获取网络套结字描述符
	int socketid;
	socketid = socket(AF_INET,SOCK_STREAM,0);
	
	//AF_INET=IPv4
	//SOCK_STREAM=socket流
	//0=协议默认
	if(socketid!=EOF)
 	{
		printf("\n获取ID成功\n");
  	}
	else
	{
                perror("\n获取ID失败\n");
        }

	//2.连接服务器
	//socket网络地址赋值 --> For AF_INET see ip(7)
	struct sockaddr_in sockaddr; //接受客户端的网络地址结构体
	sockaddr.sin_family = AF_INET;//接受客户端的网络地址结构体的大小
	sockaddr.sin_port = 5001; //5000~65535是用户段口号
	//将点分十进制的IP地址转化为32位地址,存储在sockaddr.sin_addr
	
	if(1 == inet_pton(AF_INET,"192.168.43.70",(void*)&sockaddr.sin_addr))
	{
	        printf("\n转换IP-->32位成功\n");
	}
	else
        {
		perror("\n转化IP-->位失败\n");
        }

	if(0 == connect(socketid,(struct sockaddr*)&sockaddr,sizeof(sockaddr)))
	{
		printf("\nconnet function success\n");
	}
	else
	{
		perror("connect funtion error");
	}
	//3.通信
	char buf[32] = "hello word";
	char getbuf[32] = {0};
	int ret;
	while(1)
	{
		write(socketid,buf,32);  //注意:服务器的收发的字节大小应该保持一致
		ret = read(socketid,getbuf,32);
		puts(getbuf);
		sleep(1);

		if(ret == 0)
		{
			printf("\n退出循环\n");
			break;
		}

	}
	close(socketid);
	printf("\nend\n");
}

====================================================================
ser的运行结果截取如下:
farsight@ubuntu:~/Desktop$ gcc cli.c -o cli
farsight@ubuntu:~/Desktop$ gcc ser.c -o ser
farsight@ubuntu:~/Desktop$ ./ser

获取ID成功

转换IP-->32位成功

bind function success

 listen function success

阻塞等待接入

accept function success
hello word
hello word
hello word
hello word
hello word
hello word
hello word
hello word
hello word
hello word
hello word
hello word
hello word
hello word

break

end
farsight@ubuntu:~/Desktop$ 
====================================================================
cli的运行结果截取如下:
farsight@ubuntu:~/Desktop$ ./cli

获取ID成功

转换IP-->32位成功

connet function success
HELLO WORD
HELLO WORD
HELLO WORD
HELLO WORD
HELLO WORD
HELLO WORD
HELLO WORD
HELLO WORD
HELLO WORD
HELLO WORD
HELLO WORD
HELLO WORD
HELLO WORD
^C
farsight@ubuntu:~/Desktop$ 

  • 服务器的IP地址是动态的话,将网络地址结构体的s_addr地址设置位INADDY_ANY即可
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值