一 理解网络编程和套接字

第一章 理解网络编程和套接字


重点是套接字的使用:几个函数
socket() bind() listen() accept() connect()
几个函数的使用:
socke函数的使用:

#include <sys/socket.h>
int socket(int domain,int type,int protocol); 
成功返回文件描述符,失败返回-1

bind函数的使用

 #include <sys/socket.h> 
 int bind(int sockfd,struct sockaddr *myaddr,socklen_taddrlen); 
 成功返回0,失败返回-1 

listen函数的使用

#include <sys/socket.h> 
int listen(int sockfd,int backlog); 
成功返回0,失败返回-1

accept函数的使用

#include <sys/socket.h> 
int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);

connect的函数的使用

#include <sys/socket.h>
int connect(int sockfd,struct sockaddr* aerv_addr,socklen_t addrlen);
成功返回0,失败返回-1

需要掌握的知识点:
需要重点记忆的俩概念
网络编程:编写程序是两台联网的结算及相互交换数据
套接字(socket):网络数据传输用的软件设备

以接电话为例讲述构建套接字的过程:
1.调用socket函数(安装电话机):下面的函数创建的就是相当于电话机的套接字

#include <sys/socket.h>
int socket(int domain,int type,int protocol); 成功返回文件描述符,失败返回-1

2.调用bind函数(分配电话号码):用下面函数给创建好的套接字分配地址信息(IP地址和端口号

 #include <sys/socket.h> 
 int bind(int sockfd,struct sockaddr *myaddr,socklen_taddrlen); 
 成功返回0,失败返回-1 

3.调用listen函数(连接电话线):一旦连接电话线,表示电话机为可接听状态,这是其他人可以拨打电话请求连接到该电话机,同样,这个函数就是把套接字转换成可接受连接的状态

#include <sys/socket.h> 
int listen(int sockfd,int backlog); 
成功返回0,失败返回-1

4.调用accept函数 接受对方的连接请求

  调用accept函数(拿起话筒):意味着接受了对方的连接请求,套接字同样如此,如果有人为了完成数据传输而请求连接,就需要调用以下的函数进行受理
 #include <sys/socket.h> 
int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);

重点:
总结一下:网络编程中接受连接请求的套接字创建过程如下

调用socket函数创建套接字
调用bind函数分配ip地址和端口号
调用listen函数转为可接受请求状态
调用accept函数受理连接请求


测试程序 敲一遍感受一下建立套接字的过程:

1 服务器端 hello_server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
void error_handling(char *message);
int main(int argc, char *argv[])
{
	int serv_sock;
	int clnt_sock;
	struct sockaddr_in serv_addr;
	struct sockaddr_in clnt_addr;
	socklen_t clnt_addr_size;
	char message[] = "Hello world";
	if(argc != 2){
		printf("Usage: %s <port>\n", argv[0]);
		exit(1);
	}
	serv_sock = socket(PF_INET, SOCK_STREAM, 0);
	if(serv_sock == -1){
		error_handling("socket() error");
	}

	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	serv_addr.sin_port = htons(atoi(argv[1]));
	if(bind(serv_sock,(struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1){
		error_handling("bind() error");
	}
	if(listen(serv_sock, 5) == -1){
		error_handling("listen() error");
	}
	clnt_addr_size = sizeof(clnt_addr);
	clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);

	if(clnt_sock == -1){
		error_handling("accept() error");
	}
	
	write(clnt_sock, message, sizeof(message));
	close(clnt_sock);
	close(serv_sock);
	return 0;
}
void error_handling(char* message)
{
	fputs(message,stderr);
	fputc('\n',stderr);
	exit(1);
}

2 客户端程序 hello_client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
void error_handling(char *message);
int main(int argc, char *argv[])
{
	int sock;
	struct sockaddr_in serv_addr;
	char message[] = "Hello world";
	int str_len;
	if(argc != 3){
		printf("Usage: %s <IP> <port>\n", argv[0]);
		exit(1);
	}
	sock = socket(PF_INET, SOCK_STREAM, 0);
	if(sock == -1){
		error_handling("socket() error");
	}
	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
	serv_addr.sin_port = htons(atoi(argv[2]))
	if(connect(sock,(struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1){
		error_handling("bind() error");
	}

	str_len = read(sock,message,sizeof(message) - 1);
	if(str_len == -1){
		error_handling("read() error!");
	}
	printf("message from server : %s\n",message );
	close(sock);
	return 0;
}
void error_handling(char* message)
{
	fputs(message,stderr);
	fputc('\n',stderr);
	exit(1);
}
在这里插入代码片

========================================================================================================

基于Linux的文件操作:

主要内容:
文件描述符:系统分配给文件或套接字的整数。
标准输入 输出 错误 的文件描述符分别为:0,1,2
文件IO函数: open close write read
几个函数的具体实现
open函数

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char* path,int flag);
成功返回文件描述符,失败返回-1

close函数:

#include <unistd.h>
int close(int fd);		//fd为文件 、 套接字的描述符
成功返回0,失败返回-1

write函数:

// fd:数据传输对象的文件描述符;buf:保存要传输数据的缓冲地址;nbytes:要传输数据的字节数
// 其中size_t: typedef unsigned int size_t; ssize_t: typedef signed int ssize_t
#include <unistd.h>
ssize_t write(int fd,const void * buf,size_t nbytes)

read函数

#include <unistd.h>
/** fd:显示数据接受对象的文件描述  buf:要保存的数据的缓冲地址值  nbytes:要接收数据的最大字节数*/
ssize_t read(int fd, void* buf,size_t nbytes);
成功时返回接收的字节数,(但遇到文件结尾则返回0),失败返回-1

-------------------------------------------------------------

基础知识:
文件描述符:系统分配给文件或套接字的整数。
文件描述符(文件句柄)(在LInux下为描述符,Win下称作句柄)

1.2.2 打开文件
需要两个参数:第一个是目标文件的文件名路径信息path,第二个是文件打开模式flag

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char* path,int flag);
成功返回文件描述符,失败返回-1

1.2.3 关闭文件

#include <unistd.h>
int close(int fd);		//fd为文件 、 套接字的描述符
成功返回0,失败返回-1
在这里插入代码片

注意:此函数可以关闭文件,也可以关闭套接字,再次体现了Linux系统不区分文件和套接字的特点


1.2.4 将数据写入文件

// fd:数据传输对象的文件描述符;buf:保存要传输数据的缓冲地址;nbytes:要传输数据的字节数
// 其中size_t: typedef unsigned int size_t; ssize_t: typedef signed int ssize_t
#include <unistd.h>
ssize_t write(int fd,const void * buf,size_t nbytes)

知识扫盲:以_t为后缀的数据类型
一般为了给基本数据类型赋别名,会在头文件 sys/types.h 中大量 typedef 声明,为了同程序员定义的新数据类型区分,操作系统定义的数据类型后会添加_t

通过以下实例来理解write函数

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
void error_handling(char* message);

int main(void)
{
	/* code */
	int fd;
	char buf[] = "Let's go!\n";							//写入的字符串内容
	fd = open("data.txt",O_CREAT|O_WRONLY|O_TRUNC);		//打开文件,创建|只写|清空
	if(fd == -1){
		error_handling("open() error!");				//抛出异常
	}
	printf("file descriptor: %d\n",fd);

	if(write(fd,buf,sizeof(buf)) == -1){				//向文件fd写入,字符串buf,字节数sizeof
		error_handling("write() error!");
	}
	close(fd);											//关闭文件
	return 0;
}
void error_handling(char* message)
{
	fputs(message,stderr);
	fputc('\n',stderr);
	exit(1);
}

1.2.5 读取文件中的数据
read函数的使用

#include <unistd.h>
/** fd:显示数据接受对象的文件描述  buf:要保存的数据的缓冲地址值  nbytes:要接收数据的最大字节数*/
ssize_t read(int fd, void* buf,size_t nbytes);
成功时返回接收的字节数,(但遇到文件结尾则返回0),失败返回-1

通过以下实例来理解:
文件名字;low_read.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#define BUF_SIZE 100
void error_handling(char* message);

int main(void)
{
	int fd;
	char buf[BUF_SIZE];

	fd = open("data.txt",O_RDONLY);					//打开想要读取的文件 并返回文件描述符fd
	if(fd == -1){
		error_handling("open() error\n");			//如果打开失败,抛出异常
	}
	printf("file descriptor : %d\n",fd );			

	if(read(fd,buf,sizeof(buf)) == -1){				//读取文件fd的内容,存入buf中,sizeof字节数
		error_handling("read() error!");
	}
	printf("file data: %s\n",buf);
	close(fd);										//关闭文件
	return 0;
}
void error_handling(char* message)
{
	fputs(message,stderr);
	fputc('\n',stderr);
	exit(1);
}

1.2.7 文件描述符和套接字
下面将同时创建文件和套接字,并用整数形态比较返回的文件描述符值

文件名:fd_seri.c

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/socket.h>

int main(void)
{
	int fd1,fd2,fd3;
	fd1 = socket(PF_INET,SOCK_STREAM,0);					//这里创建一个文件和两个套接字
	fd2 = open("test.dat",O_CREAT|O_WRONLY|O_TRUNC);		
	//套接字其实在Linux系统中和文件真的是一样的,在下面还要关闭它,sokect就是打开了文件
	fd3 = socket(PF_INET,SOCK_DGRAM,0);

	printf("file descriptor 1: %d\n",fd1);
	printf("file descriptor 2: %d\n",fd2);
	printf("file descriptor 3: %d\n",fd3);

	close(fd1);close(fd2);close(fd3);
	return 0;
}

========================================================================================================

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr.liang呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值