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

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

1.1理解网络编程和套接字

1.1.1网络编程和套接字概要

网络编程就是编写程序使得两台联网的计算机可以相互交换数据。

1.1.2构建电话套接字

套接字大致分为两种,一种为TCP,一种为UDP,下面以TCP为例。

  • 调用socket函数(安装电话机时候)进行的对话
  • 问:接电话需要什么?
  • 答:当然是电话机了

下面创建的就是相当于电话机的套接字:

#include <sys/socket.h>
int socket(int domain, int type; int protocol);
  • 调用bind函数(分配电话号码)时候进行的对话
  • 问:请问您的电话号码是多少?
  • 答:我的电话号码是1231233.

利用以下函数给创建好的套接字分配地址信息(IP地址和端口号)

#include <sys/socket,h>
int bind(int sockfd, struct sockaddr *myaddr, socklem_t addrlen);
  • 调用listen函数(连接电话线)时候进行的对话
  • 问:已架设完成电话机之后是否只需链接电话线
  • 答:是的,现在只需要连接电话线就可以接听电话
#include <sys/socket.h>
int listen(int sockfd, int backlog);
  • 调用accept函数(拿起话筒)时候进行的对话
  • 问:电话响了,我该怎么做
  • 答:接起来就好
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

1.1.3编写“Hello World!"服务器端

//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);
}

1.1.4构建打电话套接字

//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[30];
    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("connect() 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);
}

1.2基于Linux的文件操作

对于Linux而言,socket操作与文件操作没有任何区别,socket也被认为是文件的一种,因此在网络数据传输过程中自然可以使用文件I/O的相关函数。

1.2.1底层访问(Low-Level File Access)和文件描述符(File Descriptor)

实际上“底层”可以理解为“与标准无关的操作系统独立提供的”。
分配给标准输入输出及标准错误的文件描述符

文件描述符对象
0标准输入:Standard Input
1标准输出:Standard Output
2标准错误:Standard Error

1.2.2打开文件

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *path, int flag);
//成功返回文件描述符,失败时候返回-1
//path:文件名的字符串地址
//flag:文件打开模式信息

文件打开模式(flag参数)

打开模式含义
O_CREAT必要时创建文件
O_TRUNC删除全部现有数据
O_APPEND维持现有数据,保存到其后
O_RDONLY只读打开
O_WRONLY只写打开
O_RDWR读写打开

1.2.3关闭文件

#include <unistd.h>
int close(int fd);
//成功时候返回0,失败返回-1
//fd:需要关闭的文件或者套接字的文件描述符

1.2.4将数据写入文件

#include <unistd.h>
ssize_t write(int fd, const void * buf, size_t nbytes);
//成功时候返回写入的字节数,失败时候返回-1
//fd:显示数据传输对象的文件描述符
//buf:保存要传输数据的缓冲地址值
//nbytes:要传输数据的字节数
//此函数定义中,size_t是通过typedef声明的unsigned int类型。
//对于size_t来说,size_t前面多加一个s代表signed,即ssize_t是通过typedef声明的signed int 类型

1.2.5读取文件中的数据

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

1.3课后题

1.3.1套接字在网络编程中的作用是什么?为什么叫他为套接字?

网络编程就是编写程序让两台联网的计算机相互交换数据。在我们不需要考虑物理连接的情况下,我们只需要考虑如何编写传输软件。操作系统提供了名为“套接字”,套接字是网络传输传输用的软件设备

1.3.2在服务器端创建套接字后,会依次调用listen函数和accept函数。请比较并说明两者作用

listen:将套接字转为可接受连接方式
accept:受理连接请求,并且在没有连接请求的情况调用该函数,不会返回。直到有连接请求为止。二者存在逻辑上的先后关系

1.3.3Linux中,对套接字数据进行I/O时可以直接使用I/O相关函数;而在Windows中则不可以。原因为何?

Linux把套接字也看作是文件,所以可以用文件I/O相关函数;而Windows要区分套接字和文件,所以设置了特殊的函数

1.3.4创建套接字后一般会给它分配地址,为什么?为了完成地址分配需要调用哪些函数?

要在网络上区分来自不同机器的套接字,所以需要地址信息。分配地址是通过bind()函数实现

1.3.5Linux中的文件描述符与Windows的句柄实际上非常类似。请以套接字为对象说明他们的含义。

Linux的文件描述符是为了区分指定文件而赋予文件的整数值(相当于编号)。Windows的文件描述符其实也是套接字的整数值,其目的也是区分指定套接字。

1.3.6底层文件I/O函数与ANSI标准定义的文件I/O函数之间有何区别?

ANSI标准定义的输入、输出函数是与操作系统(内核)无关的以C标准写成的函数。相反,底层文件I/O函数是直接提供的。理论上ANSI标准I/O提供了某些机制,性能上要优于底层I/O

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

吴薯条

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

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

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

打赏作者

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

抵扣说明:

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

余额充值