2021-04-01代码解析---TCP服务器和客户端通信(网络编程)

TCP服务器和客户端通信

1.创建流程
(1)TCP服务器(被动的一方)的创建流程:
1.创建一个套接字 socket()
2.绑定IP地址和端口号 bind()
3.使得服务器处于被动等待连接的状态 listen()
4.建立连接 accept()
5.通信 send/recv() write/read()
6.关闭套接字 close()

(2)TCP客户端(主动的一方)的创建流程:
1.创建一个套接字 socket()
2.请求连接 connect()
3.通信 send/recv()
4.关闭套接字 close()

2.代码
注:由于头文件实在是太难记了,每次都会忘记,所以在头文件后面标注了使用该头文件的函数名,而且在代码注释中标明了每个函数的语法要点。(文字有点多,可能会有手抖失误的时候,如果发现了错误记得在评论区指出,我马上改正!蟹蟹!)

以下代码实现的是同一主机之间的网络通信,如果想要实现不同主机之间的通信,只需要将另一主机客户端代码中的IP地址修改成自己的即可。

(1)服务器端- - - >TcpServer.c

#include <stdio.h>
#include <unistd.h>//read(),close()
#include <sys/socket.h>//socket(),bind(),listen(),accept()
#include <netinet/in.h>//htons()
#include <arpa/inet.h>//inet_addr()

int main()
{

				/*创建套接字*/

	/*
	 * 函 数:int socket(int domain,int types,int protocol);
	 * 头文件:#include <sys/socket.h>
	 * 功 能:创建套接字
	 * 参 数:domain:协议族
	 * 		   types:套接字类型
	 * 		   protocol:0(原始套接字除外)
	 * 返回值:成功:非负套接字描述符
	 * 		  失败:-1
	 */
	int sockFd = socket(PF_INET,SOCK_STREAM,0);//参数:internet协议,流式套接字,0
	if(sockFd < 0)
	{
		perror("socket error!");
		return -1;
	}
	printf("socket ok!\n");


			/*绑定地址信息(ip+port),bind()函数,将套接字和IP进行绑定*/
	/*
	 * Internet协议地址结构
	 * struct sockaddr_in struct sockaddr_un
	 * {
	 * 		u_short sin_family; 	//地址族,PF_INET
	 * 		u_short sin_port; 		//端口
	 *      struct in_addr sin_addr;//IPV4地址
	 * }
	 */


	/*
	 * 函 数:u_short htons(u_short);
	 * 头文件:#include <netinet.h>
	 * 功 能:将主机字节序转换为网络字节序
	 * 参 数:u_short:主机字节序的16bit数据
	 * 返回值:成功:返回转换字节序后的数值
	 * 		  失败:-1
	 */


	 /*
	  * 函 数:int inet_addr(const char *strptr);
	  * 头文件:#include <arpa/inet.h>
	  * 功 能:将strptr所指的字符串转换成32位的网络字节序二进制值
	  * 参 数:strptr:字符串
	  * 返回值:二进制值
	  */


	/* 
	 * 函 数:int bind(int socketfd,struct sockaddr * my_addr,int addrlen);
	 * 头文件:#include <sys/socket.h>
	 * 功 能:绑定(将套接字和IP端口号绑定起来)
	 * 参 数:socketfd:socket()函数调用返回的套接字描述符
	 *  	   my_addr:绑定的地址
	 *  	   addrlen:地址长度
	 * 返回值:成功:0
	 * 		 失败:-1
	 */

	

	struct sockaddr_in servAddr = {0};
	servAddr.sin_family = PF_INET;
	servAddr.sin_port = htons(8888);
	servAddr.sin_addr.s_addr = inet_addr("192.168.0.88");

	int ret = bind(sockFd,(struct sockaddr *)&servAddr,sizeof(servAddr));
	if(ret < 0)
	{
		perror("bind error!");
		close(sockFd);
		return -1;
	}
	printf("bind ok!\n");
	

						/*监听(使得服务器处于被动连接状态)*/

	/*
	 * 函 数:int listen(int socketfd,int backlog);
	 * 头文件:#include <sys/socket.h>
	 * 功 能:设置监听模式
	 * 参 数:socketfd:套接字描述符
	 *  	   backlog:指定了正在等待连接的最大队列长度(它的作用在于处理可能同时出现的几个连接请求)
	 * 返回值:成功:0
	 *   	  失败:-1
	 */ 
	ret = listen(sockFd,1);
	if(ret < 0)
	{
		perror("listen error!");
		close(sockFd);
		return -1;
	}
	printf("listenind ok!\n");


 							/*建立连接*/

	/*
	 * 函 数:int accept(int socketfd,struct sockaddr * addr,socklen_t * addrlen);
	 * 头文件:#include <sys/socket.h>
	 * 功 能:建立连接
	 * 参 数:socketfd:套接字描述符
	 *   	   addr:对方地址
	 * 		   addrlen:地址长度
	 * 返回值:成功:返回建立好连接的套接字描述符
	 * 		 失败:-1
	 */ 

	int connFd = accept(sockFd,NULL,NULL);
	if(connFd < 0)
	{
		perror("accept error!");
		close(sockFd);
		return -1;
	}
	printf("accept ok!\n");


							/*接收消息*/

	/*
	 * 函 数:ssize_t read(int fd,void * buf,size_t count);
	 * 头文件:#include <unistd.h>
	 * 功 能:从文件中读取数据存放到缓冲区中,并返回实际读取的字节数
	 * 参 数:fd:文件描述符
	 * 		   buf:指定存储器读出数据的缓冲区
	 * 		   count:指定读出的字节数
	 * 返回值:成功:读到的字节数
	 * 		  0:已到达文件末尾
	 * 		  失败:-1
	 */
	char buf[1024] = {0};
	ret = read(connFd,buf,sizeof(buf));
	if(ret <0)
	{
		perror("read error!");
		close(sockFd);
		close(connFd);
		return -1;
	}
	printf("recv:%s\n",buf);


							/*关闭套接字*/	

	/*
	 * 函 数:int close(int fd);
	 * 头文件:#include <unistd.h>
	 * 功 能:关闭文件
	 * 参 数:fd:文件描述符
	 * 返回值:成功:0
	 *  	  失败:-1
	 */ 
	close(sockFd);
	close(connFd);

	return 0;
}

(2)客户端- - - >TcpClient.c

#include <stdio.h>//fgets()
#include <unistd.h>//write(),close()
#include <sys/socket.h>//socket(),listen(),accept(),connect()
#include <netinet/in.h>//htons()
#include <arpa/inet.h>//inet_addr()

int main()
{

					/*创建套接字*/

	/*
	 * 函 数:int socket(int domain,int types,int protocol);
	 * 头文件:#include <sys/socket.h>
	 * 功 能:创建套接字
	 * 参 数:domain:协议族
	 * 		   types:套接字类型
	 * 		   protocol:0(原始套接字除外)
	 * 返回值:成功:非负套接字描述符
	 * 		  失败:-1
	 */
	int sockFd = socket(PF_INET,SOCK_STREAM,0);
	if(sockFd < 0)
	{
		perror("socket error!");
		return -1;
	}
	printf("socket ok!\n");


							/*请求连接*/
	/*
	 * Internet协议地址结构
	 * struct sockaddr_in struct sockaddr_un
	 * {
	 * 		u_short sin_family; 	//地址族,PF_INET
	 * 		u_short sin_port; 		//端口
	 *      struct in_addr sin_addr;//IPV4地址
	 * }
	 */


	/*
	 * 函 数:u_short htons(u_short);
	 * 头文件:#include <netinet.h>
	 * 功 能:将主机字节序转换为网络字节序
	 * 参 数:u_short:主机字节序的16bit数据
	 * 返回值:成功:返回转换字节序后的数值
	 * 		  失败:-1
	 */


	 /*
	  * 函 数:int inet_addr(const char *strptr);
	  * 头文件:#include <arpa/inet.h>
	  * 功 能:将strptr所指的字符串转换成32位的网络字节序二进制值
	  * 参 数:strptr:字符串
	  * 返回值:二进制值
	  */


	/* 
	 * 函 数:int connect(int socketfd,struct sockaddr * serv_addr,int addrlen);
	 * 头文件:#include <sys/socket.h>
	 * 功 能:客户端用来建立绑定关系
	 * 参 数:socketfd:socket()函数调用返回的套接字描述符
	 *  	   my_addr:服务器段地址
	 *  	   addrlen:地址长度
	 * 返回值:成功:0
	 * 		 失败:-1
	 */
	struct sockaddr_in servAddr = {0};
	servAddr.sin_family = PF_INET;
	servAddr.sin_port = htons(8888);
	servAddr.sin_addr.s_addr = inet_addr("192.168.0.88");

	int ret = connect(sockFd,(struct sockaddr *)&servAddr,sizeof(servAddr));
	if(ret < 0)
	{
		perror("connect error!");
		close(sockFd);
		return -1;
	}
	printf("connect ok!\n");


							/*发送消息*/
	
	/*
	 * 函 数:ssize_t write(int fd,void * buf,size_t count);
	 * 头文件:#include <unistd.h>
	 * 功 能:将数据写入文件中,并返回实际写入的字节数
	 * 参 数:fd:文件描述符
	 * 		   buf:指定存储器读出数据的缓冲区
	 * 		   count:想要写入的字节数
	 * 返回值:成功:已写的字节数
	 * 		  失败:-1
	 */


	/*注:由于gets函数容易造成缓冲区溢出,故使用fgets()函数
	 *
	 * 函  数:char * fgets(char * s,int size,FILE *stream);
	 * 头文件:#include <stdio.h>
	 * 功  能:行输入
	 * 参  数:s:存放输入字符串的缓冲区首地址
	 *  	  size:输入的字符串长度
	 *  	  stream:对应的流
	 * 返回值:成功:s
	 * 		 失败或到达文件末尾:NULL
	 */ 
	char buf[1024] = {0};
	fgets(buf,1024,stdin);
	ret = write(sockFd,buf,sizeof(buf));
	if(ret < 0)
	{
		perror("write error!");
		close(sockFd);
		return -1;
	}
	printf("write ok!\n");


							/*关闭套接字*/	

	/*
	 * 函 数:int close(int fd);
	 * 头文件:#include <unistd.h>
	 * 功 能:关闭文件
	 * 参 数:fd:文件描述符
	 * 返回值:成功:0
	 *  	  失败:-1
	 */ 
	close(sockFd);

	return 0;
}

see you next time!(其实我知道没人看,就当做是在写日记叭~~~~~~~)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值