Linux网络编程——Socket编程步骤及常用API

目录

Sockt服务器和客户端的开发步骤

TCP

UDP

常用API

包含头文件

创建套接字(连接协议)

作用

函数原型

参数解读

返回值

地址准备(为套接字添加端口号和IP地址)

作用

函数原型

参数解读

监听网络连接

作用

函数原型

参数解读

网络连接

作用

函数原型

参数解读

返回值

客户端连接

作用

函数原型

参数解读

返回值

TCP数据收发(第一套)

(1)发送

函数原型

参数解读

(2)接收

函数原型

参数解读

返回值

TCP数据收发(第二套)

(1)发送

函数原型

参数解读

(2)接收

函数原型

参数解读

UDP数据收发(待完善)

地址转换API

字符串转网络

网络转字符串

代码示例

1、服务端与网络实现连接

2、服务端连接实现信息交流


Sockt服务器和客户端的开发步骤

TCP

connect()最好建立在listen()后,一旦监听到就建立连接。

UDP

常用API

包含头文件

#include<sys/types.h>
#include<sys/socket.h>

创建套接字(连接协议)

作用

用于根据指定的地址族、数据类型和协议来分配一个套接口的描述字及其所用的资源的函数。

函数原型
int socket(int domain,int type, int protocol);
参数解读

domain:指明所使用的协议族/域。
常用的domain类型有:

  • AF_INET IPv4——因特网域
  • AF_INET6 IPv6——因特网域
  • AF UNIX Unix——域
  • AF ROUTE——路由套接字
  • AFKEYE——钥套接字
  • AF UNSPEC——未拖定

type:指定socket类型。
常用的socket类型有:
SOCK_STREAM
TCP:流式套接字提供可靠的、面向连接的通信流:它使用TCP协议,从而保证了数据传输的正确性和顺序性。
SOCK_DGRAM
UDP:数据报套接字定义了一种无连按的服,数据通过相互独立的报文进行传输, 是无序的,并且不保证是可靠,无差错的。它使用数据报协议UDP
SOCK_RAW
允许程序使用低层协议,原始科接字允许对底层协议如IP或ICMP进行直接访问,功能强大但使用较为不便,主要用于一些协议的开发。

protocol:通常赋值 0
0表示选择type类型对应得默认协议。

  • IPPROTO_TCP——TCP传输协议
  • IPPTOTO_UDP——UDP传输协议
  • IPPROTO_SCTP——STCP传输协议
  • IPPROTO_TIPC——TIPC传输协议
返回值

成功时返回新的套接字描述符,失败返回 -1。

地址准备(为套接字添加端口号和IP地址)

作用

套接字绑定到一个地址,并制定一个端口号。 将套接字绑定一个IP地址和端口号,因为这两个元素可以在网络环境中唯一地址表示一个进程。

函数原型
int bind(int sockfd, const struct sockaddr *addr,int addrlen);
参数解读
sockfd是一个socket描述符。
*addr

是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针,指向要绑定给sockfd的协议地址结构这个地址结构根据地址创建,socket时的地址协议族的不同而不同。

addrlen第二个参数中结构体的长度

ipv4对应的结构体:

第一种:

struct sockaddr{
				unisgned short as family;	//协议族   选择TCP/UDP
				char sa data[14]; //IP+端口   以字符串形式传递
};

第二种(常用):

比较常用,但调用时需要转换成第一种结构体名字,转换格式如(struct sockaddr *)

struct sockaddr_in{
					sa_family_t sin_family; //协议族   一般是IPV4的网络协议
					in_port t sin_port; //端口号
					struct in_addr sin_addr;//IP地址结构体
					unsigned char sin_zero[8];//填充 没有实际意义,只是为跟sockaddh结构在内存中对齐这样两者才能相互转换
};

监听网络连接

作用

listen函数使用主动连接套接字变为被连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程。在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。
listen函数一般在调用bind之后-调用accept之前调用。

设置处理的最大连接数,listen()并未开始接受连线,只是设置 sockectlisten 模式,listen 函数只用于服务器端,服务器进程不知道要与谁连接,因此,它不会主动此要求与某个进程连接,只是一直监听是否有其他客户进程与之连接,然后响应该连接清求,并对它做出处理,一个服务进程可以同时处理多个客户进程的连接。主要就两个功能:将一个未连接的套接字转换为一个被动套接字(监听),规定内核为相应套接字排队的最大连接数
内核为任何一个给定监听套接字维护两个队列:
(1) 未完成连接队列,每个这样的 SYN 报文段对应其中一项:已由某个客户端发出并到达服务器,而服务正在等待完成相应的 TCP 三次握手过程。这些套接字处于SYN_REVD状态。
(2) 已完成连接队列,每个已完成 TCP 三次握手过程的客户端对应其中一项。这些套接字处于 ESTABLISHED 状态。

函数原型
int listen(SOCKET sockfd, int backlog);
参数解读
sockfdsocket系统调用返回的服务器端socket描述符
backlog指定在请求队列中允许的最大请求数

网络连接

作用

accept函数由TCP服务器调用,用于从已完成连接队列队头返回下一个已完成连接。如果已完成连接队列为空,那么进程被投入睡眠。

函数原型
int accept (int sockfd, struct sockaddr *addr, socklen_t *addrlen);	
参数解读
sockfdsocket系统调用返回的服务器端socket描述符
addr指向客户端数据结构sockaddr的指针,其中包括目的端口和IP地址
*addrlen参数二sockaddr的长度的地址,可以通过sizeof(struct sockaddr)获得
返回值

该函数的返回值是一个新的套接字描述符,返回值是表示已连接的套接字描述符,而第一个参数是服务器监听套接字描述符。一个服务器通常仅仅创建一个监听套接字,它在该服务器的生命周期内一直存在。内核为每个由服务器进程接受的客户连接创建一个已连接套接字(表示 TCP 三次握手已完成),当服务器完成对某个给定客户的服务时,相应的已连接套接字就会被关闭。

客户端连接

作用

该函数用于绑定之后的client 端(客户端),与服务器建立连接。(客户机连接主机)

函数原型
int connect (int sockfd, struct sockaddr *addr, socklen_t addrlen);
参数解读
sockfdsocket系统调用返回的服务器端socket描述符
addr指向客户端数据结构sockaddr的指针,其中包括目的端口和IP地址
addrlen参数二sockaddr的长度,可以通过sizeof(struct sockaddr)获得
返回值

成功返回0,遇到错误时返回-1,并且errno 中包含相应的错误码。

TCP数据收发(第一套)

(1)发送
函数原型
ssize_ t send(int s, const void *msg,size_t len,int flags);
参数解读
ss为已建立好连接的套接字描述符
msgmsg指向存放待发送数据的缓冲区
lenlen为待发送数据的长度
flagsflags为控制选项,一般设置为0
(2)接收
函数原型
ssize t recv(int s, void *buf,size_t len, int flags);
参数解读
ss为已建立好连接的套接字描述符
msgmsg指向存放待发送数据的缓冲区
lenlen为待发送数据的长度
flagsflags为控制选项,一般设置为0
返回值

函数返回读或写的字节个数,出错则返回-1。

TCP数据收发(第二套)

(1)发送

将buf中的nbytes个字节写入到文件描述符fd中,成功时返回写的字节数。

函数原型
ssize_t write(int fd, const void *buf,size_t nbytes);
参数解读
fdfd为已建立好连接的文件描述符
bufbuf指向存放待发送数据的缓冲区
size_t nbytessize_t nbytes为待发送数据的长度
(2)接收

从fd中读取nbyte个字节到buf中,返回实际所读的的字节数。

函数原型
ssize_t read(int fd,void *buf,size_t nbyte);
参数解读
fdfd为已建立好连接的文件描述符
bufbuf指向存放待发送数据的缓冲区
size_t nbytessize_t nbytes为待发送数据的长度

UDP数据收发(待完善)

UDP数据收发与TCP类似,常用的API是recvmsg()/sendmsg(),revfrom()/sendto0

地址转换API

字符串转网络
int inet_aton(const char* straddr,struct in_addr *addrp);

作用:把字符串形式的”192.168.1.123"转为网络能识别的格式

网络转字符串
char* inet ntoa(struct in_ addr inaddr);

作用:把网络格式的ip地址转为字符串形式

代码示例

1、服务端与网络实现连接

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

int mian()
{
	int s_fd;//定义一个套接字描述符

	s_fd = socket(AF_INET,SOCK_STREAM,0);
	if(s_fd == -1)//返回-1时表示创建失败
	{
		perror("socket");
		exit(-1);
	}
	
	struct sockaddr_in s_addr;//定义一个sockaddr_in类型的结构体(后面需要转为sockaddr类型)
	s_addr.sin_family = AF_INET;//IPV4的英特网域
	s_addr.sin_port = htons(8888);//端口号 x86主机是小端 网络是大段 需进行转换	                        
    inet_aton("127.0.0.1",&s_addr.sin_addr);//把字符串形式的”127.0.0.1”转为网络能识别的格式
    //127.0.0.1表示本机地址  ifconfig查询电脑地址
		
	bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));//需要注意第二个参数需将原来的sockaddr_in结构体类型转换成sockaddr结构体类型

	listen(s_fd,10);

	int c_fd = accept(s_fd,NULL,NULL);//需定义一个fd来接受其返回值 后续对连接的操作是基于fd  若没有接收到数据 则会一直阻塞

	printf("connect\n");
	while(1);
	
	return 0;
}

编译结果:编译运行后,程序会一直阻塞,打开另一执行程序页面,输入 telnet+电脑地址后 程序接收成功,则会输出connect。

2、服务端连接实现信息交流

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

int main()
{
	int s_fd;
	int n_read;//用于判断
	char readBuf[128];	
	char *msg = "I get your connect";

	struct sockaddr_in s_addr;
	struct sockaddr_in c_addr;
	
	memset(&s_addr,0,sizeof(struct sockaddr_in));//对数据进行清空再定义
    memset(&c_addr,0,sizeof(struct sockaddr_in));

    s_fd = socket(AF_INET,SOCK_STREAM,0);
	if(s_fd == -1)
	{
		perror("socket");
		exit(-1);
	}
	
	s_addr.sin_family = AF_INET;
	s_addr.sin_port = htons(8888);

 	inet_aton("127.0.0.1",&s_addr.sin_addr);
		
	bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));

	listen(s_fd,10);

	int clen = sizeof(struct sockaddr_in);//计算结构体c_addr的大小
	int c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);
	if(c_fd == -1)
	{
        perror("accept");
	    exit(-1);
    }
	printf("get connect :%s\n",inet_ntoa(c_addr.sin_addr));//将网络ip地址转为字符串形式 连接成功先输出此行
	
	n_read = read(c_fd,readBuf,128);//从c_fd读取128个字节到readBuf中
    if(n_read == -1)//调用失败返回-1
    {
        perror("read");
    }
    else
    {
        printf("get message:%d,%s\n",n_read,readBuf);
    }

	write(c_fd,msg,strlen(msg));
	
	return 0;
}

编译运行后,打开另一程序运行界面,输入telnet+电脑地址后 程序接收成功,则会输出connect并将IP地址以字符串形式打印出来,同时输入相应数据另一端会接收成功,实现客户端与客户端信息交流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值