2021-07-07

Linux下的基本编程方法

作为网络编程的新手,我对此也不是特别熟练,仅仅基于书本以及自己完成的实验用简单的说明加以讲解,帮助入手linux下网络编程的人更快的了解这种思想。
过段时间我会继续更新windows下的编程方法

如有错误希望指正,谢谢。

tcp协议

socket()函数

在讲述函数前希望对于socket套接字有一定的印象。
socket在英文中的含义为插座。
作为计算机与网络通信的的媒介,socket的学习是网络编程的基础。
通过在套接字绑定目的IP以及端口号,实现与服务器等其它设备的服务请求。

socket(int family,int type,int protocal)

函数的作用为创建一个新的网络套接字,返回值为int。
当返回值大于0时,套接字创建成功,失败时则返回-1;
参数列表:
int family 协议簇 :一般只有两种 AF_INET ,AF_UNIX.
在C/S模式下均使用AF_INET。
AF_UNIX作为UNIX域套接字使用。
int type 数据的类型:SOCK_STREAM 流式套接字 以及SOCK_DGRAM 数据报套接字。
流式套接字采用数据流的形式,针对于面向连接的TCP服务
数据报形式针对于面向无连接的UDP协议。
除此之外 SOCK_RAW(原始)很少使用,我也没遇到所以不再细述。
int protocol 协议:默认为0
使用方法:int fd = sockfd(AF_INET,SOCK_STREAM,0)

bind()函数

为接收客户端请求,服务器端套接字需绑定ip以及端口才接收相应的连接请求。
bind函数的作用即为绑定ip地址及端口号。
这里引入了两结构体

sockaddr 以及sockaddr_in;

两种结构体为并列关系。
由于该处是简单讲解,不对其具体内容详细列出。
sockaddr定义于#include <sys/socket.h>
其中char sa_data[14]的字符数组用于存放目的端的ip以及端口,由于难以直接对其赋值,所以采用sockaddr_in结构体临时存放ip以及端口。
sockaddr_in{
short sin_family; /AF_INET 协议簇/
u_short sin_port; /端口号,网络字节顺序/
struct in_addr sin_addr; /IP地址,网络字节顺序/
char sin_zero[8]; /填充字节,必须为全零/
}
而结构体in_addr{
u_long S_addr; 用于存放相应的32IPv4地址。
}

bind(int socket,struct sockaddr *myaddr,int addrlen)

用于将ip地址与端口号绑定至对应的socket套接字中
参数列表:
int sockfd 定义需要绑定的socket套接字
struct sockaddr *myaddr 绑定对应的ip地址与端口、协议
int addrlen 地址长度
返回值:
-1失败
0成功

struct sockaddr_in servaddr;
bzero(&servaddr,sizeof(servaddr)); //用于对结构体进行初始化
servaddr.sin_family=AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY); //INADDR_ANY绑定任何网络设备接口,适合于多IP主机以及IP地址经常变化的情况
servaddr.sin_port=htons(8086);  
if(bind(fd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)  //在这里将sockaddr_in类型结构体强制转换成sockaddr
  	{
		fprintf(stderr,"Bind error");
		exit(1);
 	 }

listen()函数

绑定地址端口后的socket作为监听socket,监听来自客户端的连接请求。

listen(int socket,int backlog)

参数列表:
int socket: :监听socket
int backlog :完成连接队列的最大长度。
返回值:
0成功
-1失败
TCP为每个监听socket维护两个队列信息。
其一为未完成连接的socket队列。
第二为已完成连接的socket队列,而backlog即为该队列长度。

if(listen(listenfd,BACKLOG)<0)
  	{
		fprintf(stderr,"Listen error");
		exit(1);
 	 }

accept()函数

accept(int socket,struct sockaddr * addr,int addrlen)

参数列表
int socket :监听socket
struct sockaddr *addr :接受的客户端的地址内容
int addrlen : 结构体长度
返回值>0成功 这时返回的为连接后的socket;
=-1则为失败

int connfd=accept(listenfd,
(struct sockaddr *)&clientaddr,
sizeof(struct sockaddr_in));

connect()函数

客户端请求连接服务器的函数
###connect(int sockfd,struct sockaddr *servaddr,int addrlen)
参数列表:
sockfd-socket描述符
servaddr-服务器地址
addrlen-地址结构长度
返回值:
0成功
-1失败

客户端使用connect前,无需对socket进行绑定,通过connect与服务器建立连接之后,该套接字即可作为新的套接字使用。
具体使用方式:

struct sockaddr_in servaddr;
bzero(&servaddr,sizeof(servaddr));
  servaddr.sin_family=AF_INET;
  servaddr.sin_port=htons(SERVER_PORT);
  if(inet_aton(127.0.0.1,&servaddr.sin_addr)==-1)  //inet_aton用于将字符串格式转为相应的ipv4格式的ip地址
  {
	fprintf(stderr,"Inet_aton error");
	exit(1);
  }
  if(connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
  {
	fprintf(stderr,"Connect error");
	exit(1);
  }

简单读写函数

write(int socket,char *buf,int len)

参数:
int socket :向指定的socket中写入数据
char *buf :写入的内容;
int length : buf的长度
返回值:
-1 失败
其他 返回写入内容的长度
系统发送缓冲区中空间大于参数len时返回len

read(int socket,char*buf,int len)

int socket :从指定的socket中写入数据
char *buf :希望读进的缓存区;
int length : 缓存区的长度
返回值:
-1 失败
其他 返回读入内容的长度

close()关闭套接字

close(int socket)

关闭socket
参数:
int socket :socket描述符
返回值
0-成功,-1-失败

示例代码如下:
服务器端

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

#define MAXDATASIZE 128
#define PORT 3000
#define BACKLOG 5

int main(int argc,char **argv){
	int sockfd,new_fd,nbytes,sin_size;
	char buf[MAXDATASIZE];
	struct sockaddr_in servaddr,clientaddr;
	
	//1.创建服务器网络端点
	sockfd=socket(AF_INET,SOCK_STREAM,0);
	if(sockfd==-1){
		printf("can't create socket\n");
		exit(1);
	}
	//填充地址
	bzero(&srvaddr,sizeof(servaddr));
	servaddr.sin_family=AF_INET;
	servaddr.sin_port=htons(PORT);
	
	if(inet_aton("127.0.0.1",&servaddr.sin_addr)==-1){
		printf("addr convert error\n");
		exit(1);
	}
	
	//srvaddr.sin_addr.s_addr=htonl(INADDR_ANY);
	//2.绑定服务器地址和端口
	if(bind(sockfd,(struct sockaddr *)&servaddr,sizeof(struct sockaddr))==-1){
		printf("bind error\n");
		exit(1);
	}
	//3. 监听端口
	if(listen(sockfd,BACKLOG)==-1){
		printf("listen error\n");
		exit(1);
	}
	for(;;){
		//4.接受客户端连接
		sin_size=sizeof(struct sockaddr_in);
		if((new_fd=accept(sockfd,(struct sockaddr *)&clientaddr,&sin_size))==-1){
			printf("accept errot\n");
			continue;
		}
		printf("client ip:%s\n",inet_ntoa(clientaddr.sin_addr));
		printf("client port:%d\n",ntohs(clientaddr.sin_port));
		//5.接收请求
		nbytes=read(new_fd,buf,MAXDATASIZE);
		buf[nbytes]='\0';
		printf("client:%s\n",buf);
		
		//6.回送响应
		sprintf(buf,"wellcome!");
		write(new_fd,buf,strlen(buf));
		//关闭socket
		close(new_fd);
	}
//关闭socket
	close(sockfd);
	
	return 0;
}

客户端

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

#define MAXDATASIZE 128
#define PORT 3000

int main(int argc,char **argv){
	int sockfd,nbytes;
	char buf[MAXDATASIZE];
	struct sockaddr_in servaddr;
	//1.创建网络端点
	sockfd=socket(AF_INET,
SOCK_STREAM,
0);
	if(sockfd==-1){
		printf("can;t create socket\n");
		exit(1);
	}
	//指定服务器地址(本地socket地址采用默认值)
	bzero(&servaddr,sizeof(servaddr));
	srvaddr.sin_family=AF_INET;
	srvaddr.sin_port=htons(PORT);
	if(inet_aton("127.0.0.1",&servaddr.sin_addr)==-1){
		printf("addr convert error\n");
		exit(1);
	}
	//2.连接服务器
	if(connect(sockfd,(struct sockaddr *)&servaddr,sizeof(struct sockaddr))==-1){
		printf("connect error\n");
		exit(1);
	}
	//3.发送请求
	sprintf(buf,"hello");
	write(sockfd,buf,strlen(buf));
	//4.接收响应
	if((nbytes=read(sockfd,buf,MAXDATASIZE))==-1){
		printf("read error\n");
		exit(1);
	}
	buf[nbytes]='\0';
	printf("srv respons:%s\n",buf);
	//关闭socket
	close(sockfd);
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值