Linux应用程序开(day19) ── TCP网络编程、UDP编程

TCP编程

sockaddr_in套接字

已经提供好了套接字结构体,我们可以直接使用。

struct sockaddr_in{
sa_family_t sin_family; //2字节
in_port_t sin_port; //2字节
struct in_addr sin_addr; //4字节
unsigned char sin_zero[8]; //8字节
};

sockaddr通用套接字

使格式统一,使不同格式的都能传入套接字函数,我们可以强制转换成同意套接字。

struct sockaddr{
sa_family_t sa_family; //2字节
char sa_data[14]; //14字节
};

inet_pton()函数

#include <arpa/inet.h>
int inet_pton(int family, const char*strptr, void *addrptr);

功能:将点分十进制数串转换成32位无符号整数
参数:
family:协议族
strptr :点分十进制数串
addrptr:32位无符号整数的地址
返回值:成功返回1,失败返回其他

inet_ntop()函数

#include <arpa/inet.h>
 const char *inet_ntop(int family, constvoid *addrptr, char *strptr, size_t len);

功能:将32位无符号整数转换成点分十进制数串
参数:
family:协议族
addrptr:32位无符号整数的地址
strptr :点分十进制数串
len:strptr缓存区长度
len的宏定义:
#define INET_ADDRSTRLEN 16 //ipv4
#define INET6_ADDRSTRLEN 46 // ipv6
返回值:成功返回字符串首地址,失败返回NULL

创建套接字

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

功能:创建套接字
参数:
family:协议族
       AF_INET,AF_INET6AF_LOCAL,AF_ROUTE,AF_KEY
type:套接字类型
      SOCK_STREAM,SOCK_DGRAM,SOCK_RAW,SOCK_SEQPACKET
protocol:协议类别
      0,IPPROTO_TCP,IPPROTO_UDP,IPPROTO_SCTP
返回值:创建的套接字
创建的套接字的特点:
      系统不会分配端口,需要绑定端口;创建的是主动套接字,作为服务器需要被动的等待别人连接。

服务端

本地协议与套接字绑定

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

功能:将本地协议与套接字绑定
参数:
sockfd: socket套接字
myaddr: 指向特定于协议的地址结构指针
addrlen:该地址结构的长度
返回值:成功:返回0,失败:其他

监听

 int listen(int sockfd, int backlog);

功能;将套接字的主动修改为被动;为套接字创建一个链接队列,用来记录链接到该套接字的所有连接
参数:
sockfd:要监听的套接字地址
backlog:连接队列的长度
返回值:成功返回0;失败返回其他

获取连接

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

功能:从连接队列中获取一个连接,若连接队列为空,则进入睡眠等待。
参数:
sockfd: socket监听套接字
cliaddr: 用于存放客户端套接字地址结构
addrlen:套接字地址结构体长度
返回值:已连接套接字

客户端

连接服务器

int connect(int sockfd,const structsockaddr *addr,socklen_t len);

功能:与服务器建立连接
参数:
sockfd:socket套接字
addr: 需连接的服务器地址结构
addrlen:地址结构体长度
返回值:成功返回0,失败返回其他

发送数据

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

功能:发送数据(不能发送长度为0的数据)
参数:
sockfd: socket套接字
buf: 待发送数据缓存区的地址
nbytes: 发送缓存区大小(以字节为单位)
flags: 套接字标志(常为0)
返水着:成功发送的字节数

接收数据

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

功能:接受数据
参数:
sockfd: 套接字
buf: 指向接收网络数据的缓冲区
nbytes: 接收缓冲区的大小(以字节为单位)
flags: 套接字标志(常为0)
返回值:成功接收到字节数

关闭连接

close();

关闭一个代表已连接套接字将导致另一端接收到一个0长度的数据包
做服务器时:
关闭socket创建的监听套接字将导致服务器无法继续接受新的连接,但不会影响已经建立的连接
关闭accept返回的已连接套接字将导致它所代表的连接被关闭,但不会影响服务器的监听
做客户端时:
关闭连接就是关闭连接,不意味着其他
客户端:

int main(int argc, char *argv[])
{
	unsigned short port = 8000;        // 服务器的端口号
	char *server_ip = "47.98.51.177";      // 服务器ip地址
	char send_buf[512] = "hello every!";	
	char recv_buf[512] = "";
	int sockfd = 0;
	int err_log = 0;
	struct sockaddr_in server_addr;

	if( argc > 1 )		//函数传参,可以更改服务器的ip地址									
	{		
		server_ip = argv[1];
	}	
	
	if( argc > 2 )	   //函数传参,可以更改服务器的端口号									
	{
		port = atoi(argv[2]);
	}

	bzero(&server_addr,sizeof(server_addr));     // 初始化服务器地址
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(port);
	inet_pton(AF_INET, server_ip, &server_addr.sin_addr);

	sockfd = socket(AF_INET, SOCK_STREAM, 0);        // 创建通信端点:套接字
	if(sockfd < 0)
	{
		perror("socket");
		exit(-1);
	}
	
	err_log = connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));      // 主动连接服务器
	if(err_log != 0)
	{
		perror("connect");
		close(sockfd);
		exit(-1);
	}
	
	send(sockfd, send_buf, strlen(send_buf), 0);   // 向服务器发送信息
	recv(sockfd, recv_buf, sizeof(recv_buf), 0);   // 接收服务器发回的信息
	printf("%s\n", recv_buf);
	
	close(sockfd);
	return 0;
}

服务端:

int main(int argc, char *argv[])
{
	char recv_buf[2048] = "";			// 接收缓冲区
	int sockfd = 0;						// 套接字
	int connfd = 0;
	int err_log = 0;
	struct sockaddr_in my_addr;		// 服务器地址结构体
	unsigned short port = 8000;			// 监听端口	
	
	if(argc > 1)						// 由参数接收端口
	{
		port = atoi(argv[1]);
	}
	
	printf("TCP Server Started at port %d!\n", port);
	
	sockfd = socket(AF_INET, SOCK_STREAM, 0);   // 创建TCP套接字
	if(sockfd < 0)
	{
		perror("socket");
		exit(-1);
	}
	
	bzero(&my_addr, sizeof(my_addr));	     // 初始化服务器地址
	my_addr.sin_family = AF_INET;
	my_addr.sin_port   = htons(port);
	my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	
	printf("Binding server to port %d\n", port);
	
	err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));
	if( err_log != 0)
	{
		perror("binding");
		close(sockfd);		
		exit(-1);
	}
	
	err_log = listen(sockfd, 10);
	if(err_log != 0)
	{
		perror("listen");
		close(sockfd);		
		exit(-1);
	}	
	
	printf("Waiting client...\n");
	
	while(1)
	{
		size_t recv_len = 0;
		struct sockaddr_in client_addr;		   // 用于保存客户端地址
		char cli_ip[INET_ADDRSTRLEN] = "";	    // 用于保存客户端IP地址
		socklen_t cliaddr_len = sizeof(client_addr);      // 必须初始化!!!

		connfd = accept(sockfd, (struct sockaddr*)&client_addr, &cliaddr_len);       // 获得一个已经建立的连接
		if(connfd < 0)
		{
			perror("accept");
			continue;
		}
		
		inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);
		printf("client ip = %s\n", cli_ip);
		
		while((recv_len  = recv(connfd, recv_buf, sizeof(recv_buf), 0)) > 0)
		{
			send(connfd, recv_buf, recv_len, 0); 
		}
		
		close(connfd);     //关闭已连接套接字
		printf("client closed!\n");
	}
	
	close(sockfd);         //关闭监听套接字
	return 0;
}

UDP编程

发送数据

ssize_t  sendto(int sockfd,const void*buf, size_t nbytes,int flags, conststruct sockaddr *to,socklen_t addrlen);

功能:发送UDP数据
参数:
sockfd:套接字
buf:发送数据缓冲区
nbytes:发送数据缓冲区的大小
flags:一般为0
to:指向目的主机地址结构体的指针
addrlen:to所指向内容的长度
注意:可以发送长度为0的数据包
返回值:成功返回发送的字符数,失败返回-1

接收数据

ssize_t  recvfrom(int sockfd, void *buf,size_t nbytes,int flags,structsockaddr *from, socklen_t *addrlen);

功能:接受UDP数据
参数:
sockfd:套接字
buf: 接收数据缓冲区
nbytes:接收数据缓冲区的大小
flags: 套接字标志(常为0)
from: 用于存放发送方信息的地址结构体指针
addrlen: from所指内容的长度
注意:若from、addrlen两个参数为NULL,则表示不关心数据来源
返回值:成功返回接受到的字符数,失败返回-1
例程
服务器端:

void main(){
	
	int socketfd,ret;
	struct sockaddr_in my_addr;
	unsigned short port = 8000;
	//创建套接字
	socketfd = socket(AF_INET,SOCK_DGRAM,0);
	if(socketfd < 0)
	{
		perror("创建socket失败\n");
		exit(-1);
	}
	bzero(&my_addr,sizeof(my_addr));
	my_addr.sin_family = AF_INET;
	my_addr.sin_port   = htons(port);
	my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	printf("要绑定的端口:%d ,16进制显示:%x ,转换后的端口%x \n",port,port,my_addr.sin_port );
	//绑定
	ret = bind(socketfd,(struct sockaddr*)&my_addr,sizeof(my_addr));
	if(ret != 0)
	{
		perror("绑定失败\n");
		exit(-1);
	}
	printf("等待客户端连接\n");
	while(1)
	{
		char buff[1024] = "";
		int recv_len = 0;
		struct sockaddr_in client_addr;
		char ip[INET_ADDRSTRLEN]="";
		socklen_t len = sizeof(client_addr);
		
		
		recv_len = recvfrom(socketfd,buff,sizeof(buff),0,(struct sockaddr*)&client_addr,&len);
		inet_ntop(AF_INET,&client_addr.sin_addr,ip,INET_ADDRSTRLEN);
		printf("连接的客户端ip为:%s",ip);
		
		sendto(socketfd,buff,sizeof(buff),0,(struct sockaddr*)&client_addr,len);
		
		
	}
	
	
	
}

客户端:

void main(){
	int socketfd,ret;
	struct sockaddr_in my_addr;
	unsigned short port = 8000;
	char serv_ip[INET_ADDRSTRLEN]="127.0.0.1";
	
	
	socketfd = socket(AF_INET, SOCK_DGRAM, 0); 
	if(socketfd < 0)
	{
		perror("创建socket失败\n");
		exit(-1);
	}
	bzero(&my_addr,sizeof(my_addr));
	my_addr.sin_family = AF_INET;
	my_addr.sin_port   = htons(port);
	inet_pton(AF_INET, serv_ip, &my_addr.sin_addr);
	printf("准备向服务器发送数据\n");
	while(1)
	{
		char str[100] = "helloworld";
		char recv[100] = "";
		
		sendto(socketfd,str,sizeof(str),0,(struct sockaddr*)&my_addr, sizeof(my_addr));
		recvfrom(socketfd,recv,sizeof(recv),0,NULL,NULL);
		printf("接收到的回传数据:%s \n",recv);
	}

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值