Linux中网络编程常用函数详解

本片博客主要介绍TCP编程,包括TCP常用函数的介绍,以及实例演示

1、函数说明

在编程总常用的基本函数有socket()、bind()、listen()、accept()、send()、sendto()、recvfrom()等,下面开始介绍这些函数的功能以及使用方法:

soscket():该函数用于创建一个套接字,同时指定协议与类型。socket返回的fd叫做监听fd,是用来监听客户端的,不能用来和任何客户端进行读写;accept返回的fd叫做连接fd,用来和连接那端的客户端程序进行读写。

所需头文件

#include<sys/socket.h>

#include <sys/types.h>

函数原型 int socket(int domain, int type, int protocol);
函数传入值 domain:协议族 AF_INET:IPv4协议
AF_INET6:IPv6协议
AF_LOCAL:UNIX域协议
AF_ROUTE:路由套接字
AF_KEY:密钥套接字
type:套接字类型 SOCK_STREAM:流式套接字
SOCK_DGRAM:数据报套接字
SOCK_RAW:原始套接字
protocol:0(原始套接字除外)
函数返回值 成功:非负套接字描述符
错误:-1

bind():该函数将保存在相应地址结构中的地址信息和套接字进行绑定。它主要用于服务器端,客户端创建的套接字可以不绑定地址。绑定时一般需要指定IP地址和端口号,否则内核会随意分配一个临时端口给套接字。IP地址可以直接指定0本机的IP地址(如inet_addr("192.168.1.123")),或者使用宏INADDR_ANY,允许将套接字与服务器的任意网络接口(如eth0、eth0:1、eth1等)进行绑定。

所需头文件 #include <sys/types.h>
函数原型 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
函数传入值 sockfd:套接字描述符
addr:绑定的地址
addrlen:地址长度
函数返回值 成功:0
错误:-1

listen():在服务端程序成功建立套接字并于地址进行绑定之后,通过调用listen函数将套接字设置成监听模式(被动模式),准备接受客户端的连接请求。

注意:backlog参数,服务器在调用listen和accept后,就会阻塞在accept函数上,accpet函数返回后循环调用accept函数等待客户的TCP连接。如果这时候又大量的用户并发发起connect连接,那么在listen有队列上限(最大可接受TCP的连接数)的情况下,有多少个connect会成功了。试验证明,当连接数远远高于listen的可连接数上限时,客户端的大部分TCP请求会被抛弃,只有当listen监听队列空闲或者放弃某个连接时,才可以接收新的连接。

参考:https://blog.csdn.net/sukhoi27smk/article/details/11903415

扫描二维码关注公众号,回复: 5123297 查看本文章
所需头文件 #include<sys/socket.h>
函数原型 int listen(int sockfd, int backlog);
函数传入值 sockfd:套接字描述符
backlog:请求队列中允许的最大请求,大多数系统默认为5
函数返回值 成功:0
错误:-1

accept():服务器端通过调用accept()函数等待并接受客户端的连接请求。建立好TCP连接之后,该函数会返回一个已连接的套接字。返回值是一个fd,accept正确返回就表示我们已经和前来连接我的客户端之间建立了一个TCP连接了,以后我们就要通过这个连接来和客户端进行读写操作,读写操作就需要一个fd,这个fd就由accept来返回了。

所需头文件 #include<sysy/socket.h>
函数原型 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
函数传入值 sockfd:套接字描述符
addr:用于保存客户端地址
addrlen:地址长度
函数返回值 成功:建立好连接的套接字描述符
错误:-1

connect():客户端通过该函数向服务器端的监听套接字发送请求

所需头文件 #include<sys/socket.h>
函数原型 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
函数传入值 sockfd:套接字描述符
addr:服务器端地址
addrlen:地址长度
函数返回值 成功:0
错误:-1

send()和recv():这两个函数通常在TCP通信过程中用于发送和接收数据,也可用在UDP中。

所需头文件 #include
函数原型 ssize_t send(int sockfd, const void *buf, size_t len, int flags);
函数传入值 sockfd:套接字描述符
buf:发送缓冲区的地址
flags:一般为0
len:发送数据的长度
函数返回值 成功:实际发送的字节数
错误:-1
所需头文件 #include
函数原型 ssize_t recv(int sockfd, const void *buf, size_t len, int flags);
函数传入值 sockfd:套接字描述符
buf:存放接收数据的缓冲区
flags:一般为0
len:接收数据的长度
函数返回值 成功:实际接收到的字节数
错误:-1

sendto()和recvfrom():这两个函数通常在UDP通信过程中用于发送和接收数据。当用在TCP时,后面的几个与地址有关的参数不起作用,函数作用等同于send()和recv()

所需头文件 #include<sys/socket.h>
函数原型 ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
函数传入值 sockfd:套接字描述符
buf:发送缓冲区首地址
len:发送数据的长度
flags:一般为0
dest_addr:接收方的IP地址和端口号
addrlen:地址长度
函数返回值 成功:实际发送的字节数
错误:-1
所需头文件 #include<sys/socket.h>
函数原型 ssize_t recvfrom(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *src_addr, socklen_t addrlen);
函数传入值 sockfd:套接字描述符
buf:接收缓冲区首地址
len:接收数据的长度
flags:一般为0
dest_addr:发送方的IP地址和端口号
addrlen:地址长度
函数返回值 成功:实际接收的字节数
错误:-1

3、编程示例

示例分两部分,一部分是服务器,一部分是客户端

流程图如下:

/*
server.c

*/

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


#define BUF_SIZE 128

int main(int argc, char *argv[])
{
	int sockfd, connfd;
	struct sockaddr_in servaddr, cliaddr;
	char buf[BUF_SIZE] = {0};
	socklen_t peerlen;
	
	if(argc < 3)
	{
		printf("Usage:%s <IP> <port>\n", argv[0]);	//提示输入
		exit(-1);
	}
	
	/*建立socket连接*/
	
	if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		perror("socket");
		exit(-1);
	}
	printf("sockfd = %d\n", sockfd);
	
	/*设置soscket_in结构体中相关参数*/
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(atoi(argv[2]));		//把字符串转换成整型数,然后转换成对应的网络字节序
	servaddr.sin_addr.s_addr = inet_addr(argv[1]);	//sin_addr这个结构体中只有一个元素
	
	/*绑定函数bind(),将socket描述符与本地的Ip与端口绑定*/
	if(bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
	{
		perror("bind");
		exit(-1);
	}
	printf("bind success\n");
	
	/*调用listen()函数,设置监听模式*/
	if(listen(sockfd, 10) < 0)
	{
		perror("listen");
		exit(-1);
	}
	printf("listen success\n");
	
	/*调用accept()函数,等待客户端的连接*/
	peerlen = sizeof(cliaddr);
	while(1)
	{
		
		if((connfd = accept(sockfd, (struct sockaddr*)&cliaddr, &peerlen)) < 0)	//程序会阻塞在accept这里,直到有客户端来连接
		{
			perror("accept");
			exit(-1);
		}
		printf("connect success\n");
		/*调用recv()函数接收客户端发送的数据*/
		memset(buf, 0, sizeof(buf));
		if(recv(connfd, buf, BUF_SIZE, 0) == -1)
		{
			perror("recv");
			exit(-1);
		}
		printf("Receve a message: %s", buf);
		strcpy(buf, "welcome to server\n");
		send(connfd, buf, BUF_SIZE, 0);
		
		close(connfd);
	}
	
	close(sockfd);
	exit(0);	
}
/*
client.c

*/

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


#define BUF_SIZE 128

int main(int argc, char *argv[])
{
	int sockfd;
	struct sockaddr_in servaddr;
	char buf[BUF_SIZE] = {"hello Server"};
	
	if(argc < 3)
	{
		printf("Usage:%s <IP> <port>\n", argv[0]);	//提示执行程序是 传递的参数
		exit(-1);
	}
	
	/*建立socket*/
	
	if(sockfd = socket(AF_INET, SOCK_STREAM, 0) < 0)
	{
		perror("socket");
		exit(-1);
	}
	printf("listenfd = %d\n", sockfd);
	
	/*设置soscket_in结构体中相关参数*/
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(atoi(argv[2]));		//把字符串转换成整型数,然后转换成对应的网络字节序
	servaddr.sin_addr.s_addr = inet_addr(argv[1]);	//sin_addr这个结构体中只有一个元素
		
	if(connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1)	//程序会阻塞在accept这里,直到有客户端来连接
	{
		perror("connect");
		exit(-1);
	}
	
	send(sockfd, buf, BUF_SIZE, 0);
	/*调用recv()函数接收客户端发送的数据*/
	if(recv(sockfd, buf, BUF_SIZE, 0) == -1)
	{
		perror("recv");
		exit(-1);
	}
	printf("Receve a message: %s", buf);
	
	close(sockfd);

	exit(0);	
}

运行结果

猜你喜欢

转载自blog.csdn.net/David_361/article/details/86509870
今日推荐