网络通信搭建需要先建立服务器
服务器搭建步骤如下:
1、创建socket网络套接字
socket
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
功能:生成一个具有网络属性的文件描述符
参数:
domain地址族
AF_UNIX, AF_LOCAL Local communication unix(7)
AF_INET IPv4 Internet protocols ip(7)
AF_INET6 IPv6 Internet protocols ipv6(7)
type协议类型
SOCK_STREAM TCP协议
SOCK_DGRAM UDP协议
SOCK_RAW 原始,不需要协议,不安全
protocol
默认为0,代表前面参数生效
返回值:
成功返回具有网络属性的套接字sockfd
失败,返回-1,并设置错误码
2、绑定自己的IP和端口
2>绑定自己的IP地址和端口号
bind
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
功能:绑定IP地址和端口号的值到文件描述符sockfd(返回值)
参数:
sockfd:socket函数制造的套接字
addr:给套接字IP地址和端口号赋值结构体指针
addrlen:结构体的长度
返回值:
成功返回0
失败返回-1,并设置错误码
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];14个字节
}
该结构体不适用:
1>长度为14个字节 IP和端口号共6个字节
2>多出来8个字节,无法填充
3>无法判断赋值顺序,IP在前?还是在后?
struct sockaddr_in{
sa_family_t sin_family; //地址族
uint16_t sin_port; //端口号
struct in_addr sin_addr; //32位IP地址
char sin_zero; //预留未使用,自动填充0
};
struct in_addr{
In_addr_t s_addr; //32位IPv4地址
};
大小端序
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
小端转大端
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
大端转小端
IP地址从点分十进制转换为网络二进制
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
!int inet_aton(const char *cp, struct in_addr *inp);
!! int inet_ntoa(); //网络二进制转回我们熟悉点分十进制
in_addr_t inet_addr(const char *cp);
功能:
将字符串IP地址从点分十进制转换为网络二进制
参数:
字符串IP地址,"192.168.90.X"
返回值:
成功返回的,你需要的网络二进制
失败返回,INADDR_NONE
3、监听
listen
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
功能:
用来限制同一时间内连接进来的最大数量,
目的保护服务器不发生崩溃
参数:
sockfd:套接字
backlog:一般写8,服务器允许的同一瞬间接入数量
返回值:
成功返回0
失败返回-1,并设置错误码
4、等待客户连接
4>等待客户端连接
accept
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能:
等待客户端连接(阻塞)
参数:
sockfd:套接字
addr:结构体指针用来保存客户端的数据
addrlen:结构体指针的长度的指针
返回值:
成功返回客户端的sockfd
失败返回-1,并设置错误码
5、收发信息
1>接收
recv
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能:
接收数据
参数:
sockfd:服务器那边的是accept制造出来sockfd
buf:接收数据存在的缓冲区
len:缓冲区的长度
flags:设置为0,可阻塞
返回值:
>0,成功返回接收到的字节数
=0,意味着客户端异常断开(ctrl C)
失败返回-1,并设置错误码
2>发送
send
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
功能:
发送数据
参数:
sockfd:发送给谁
buf:发送数据存在的缓冲区
len:缓冲区的长度
flags:设置为0,可阻塞
返回值:
成功返回发送的字节数
失败返回-1,并设置错误码
客户端搭建步骤如下:
1、连接服务器
5>连接服务器
connect
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:
连接服务器
参数:
sockfd:套接字
addr:声明服务器serfd的结构体指针,我们的clifd通过结构体里面的IP地址和端口号找到serfd
addrlen:结构体指针的长度
返回值:
成功返回0
失败返回-1,并设置错误码
示例:
服务器:
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
int main(void)
{
//1>创建socket套接字
int serfd;
serfd = socket(AF_INET,SOCK_STREAM,0);
if(serfd<0)//返回值判断
{
perror("socket");
return -1;
}
printf("serfd: %d\n",serfd);
//2>绑定IP地址和端口号,并赋值
struct sockaddr_in ser_addr;
ser_addr.sin_family = AF_INET;
ser_addr.sin_port = htons(8888);
ser_addr.sin_addr.s_addr=inet_addr("192.168.90.6");
int ret;
ret=bind(serfd, (struct sockaddr *)&ser_addr,sizeof(ser_addr));
if(ret<0)//返回值判断
{
perror("bind");
return -1;
}
printf("绑定成功,套接字网络属性已配置\n");
//3>监听
ret = listen(serfd,8);
if(ret<0)//返回值判断
{
perror("listen");
return -1;
}
printf("监听开始,保护服务器中*-*\n");
//4>等待客户端连接
struct sockaddr_in cli_addr;
int addlen = sizeof(cli_addr);
int clifd;
clifd = accept(serfd,(struct sockaddr *)&cli_addr,&addlen);
if(clifd<0)//返回值判断
{
perror("accept");
return -1;
}
printf("有客户连接进来了!\n");
printf("客户的IP地址是 %s 端口号是 %d\n",inet_ntoa(cli_addr.sin_addr),ntohs(cli_addr.sin_port));
//5接收
char buf[50];
bzero(buf,sizeof(buf));
while(1){
recv(clifd,buf,sizeof(buf),0);//阻塞
//if(ret)
//{}
printf("客户端说:%s\n",buf);
}
return 0;
}
客户端
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
int main(void)
{
//1>创建具有网络属性的套接字
int clifd;
clifd = socket(AF_INET,SOCK_STREAM,0);
if(clifd<0)
{
perror("SOCKET");
return -1;
}
printf("clifd: %d\n",clifd);//2>声明服务器的IP地址和端口号,让clifd有能力去找到对面的serfd
struct sockaddr_in ser_addr;
ser_addr.sin_family = AF_INET;
ser_addr.sin_port = htons(8888);
ser_addr.sin_addr.s_addr=inet_addr("192.168.90.6");
//3>连接服务器
int ret;
ret = connect(clifd,(struct sockaddr *)&ser_addr,sizeof(ser_addr));
if(ret<0)//返回值判断
{
perror("connect");
return -1;
}
printf("连接服务器成功\n");
//4>发送
//因为上面声明了服务器的IP地址和
char buf[50];
bzero(buf,sizeof(buf));
while(1){
scanf("%s",buf);
send(clifd,buf,sizeof(buf),0);//阻塞
}
return 0;
}
简单记录一下网络服务器客户端搭建的基本流程。