网络编程含义:
网络编程从大的方面说就是对信息的发送到接收,中间传输为物理线路的作用。
本文介绍的是基于tcp协议的套接字网络编程。网络编程必备的三素:1ip地址 2 端口号 3数据协议(TCP, UDP)。
TCP/UDP对比
1 . TCP 面向连接(如打电话要先拨号建立连接);UDP 是无连接的,即发数据之前,不需要建立连接。
2 . TCP 提供可靠的服务,而UDP 不可靠。
3 .TCP 面向字节流,实际上是TCP 把数据堪
4 . TCP 的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道。
端口号作用
一台拥有IP 地址的主机可以提供许多服务器,比如 Web服务,FTP 服务,SMTP服务等;那么是如何来区分这些服务的呢?实际上是通过“IP地址+端口号”来区分。端口提供了一种访问通道。
字节序
字节序是指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。
字节序分为大端字节序和小段字节序。
大端字节序:将高位字节存储在起始地址;
小端字节序:将地位字节存储在起始地址;
网络字节序使用的是大端字节序,所以在网络编程中需要将IP地址和端口号转换位大端字节序。
相关API
1 . 创建套接字
int socket(int domain, int type,int protocol);
成功返回套接字描述符,失败返回-1
domain
指明所使用的协议族 通常为 AF_INET ,表示互联网协议族(TCP/IP协议族)
type 参数 指定socket 的类型
SOCK_STREAM 流式套接字提供可靠的,面向连接的通信流,它使用TCP 协议。
SOCK_DGRAM 数据报套接字定义了一种无连接的服,数据通
相互独立的报文进行传输,并且不保证是可靠的,无差错的。
protocol 通常赋值 0 0选择type类型对应的默认协议。
2 .IP号和端口号与相应描述字符赋值函数
int bind (int sockfd,const struct sockaddr *addr, socklen_t addrlen)
第一个参数 sockfd 是一个socket 文件描述符
第二个参数 结构体指针 一般使用第二种形式 结构体如下
struct sockaddr
{
unisgned short as_family;
char sa_data[14];
};
struct sockaddr_in
{
sa_family_t sin_family; //协议族
in_port_t sin_port ; // 端口号
struct in_addr sin_addr; // IP 地址
unsigned char sin_zero[9]; // 填充 没有实际意义
};
第三个参数为结构体大小
端口号转换
uint16_t htons(uint16_t host16bitvalue); // 返回网络字节序的值;
uint16_t ntohs(uint16_t net16bitvalue); //返回主机字节序的值;
IP 地址转换
int inet_aton(const char *straddr , struct in_addr *addrp ); // 把字符串形式的 IP地址 转为网络能识别的各式
char *inet_ntoa(struct in_addr inaddr); // 把网络格式的IP地址转为字符串形式
3 . listen()函数: 监听设置函数
int listen (int sockafd, int backlog); //设置能处理的最大连接数
第一个参数 sockfd 是服务端socket 描述符
第二个参数 指定在请求队列中的最大请求数
4 . int accept (int sockfd, struct sockaddr *addr, socklen_t *addrlen);
返回值是一个新的套接字描述符 ,表示已连接的套接字描述符;
第一个参数 sockfd 是服务端socket 描述符
第二个参数 addr 用来返回已连接的对端(客户端)的协议地址
第三个参数 addrlen为第二个参数结构体大小指针
5 . connect 函数用来绑定客户端,与服务端建立连接
int connect (int sockfd, const struct sockaddr *addr, socklen_t addrlen);
返回值 ,成功返回0 失败返回 -1
第一个参数 是调用socket 函数返回的套接字描述符
第二个参数 是上面 bind 函数提到的结构体指针
第三个参数是第二个参数结构体的大小
服务端代码
#include<stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
//#include<linux/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int s_fd;
char read_buf[128];
//1 socket
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<0)
{
perror("socket");
exit(-1);
}
s_addr.sin_family=AF_INET;
s_addr.sin_port=htons(6868);
inet_aton("192.168.1.11",&s_addr.sin_addr);
//2 bind
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
//3 listen
listen(s_fd,10);
//4 accept
int len=sizeof(struct sockaddr_in);
int c_fd=accept(s_fd,(struct sockaddr *)&c_addr,&len);//没人连接时会阻塞
if(c_fd==-1)
{
perror("connet");
}
printf("get connet:%s\n",inet_ntoa(c_addr.sin_addr));
int n_read=read(c_fd,read_buf,128);
if(n_read==-1)
{
perror("read");
}
printf("n_read=%d readnuf:%s\n",n_read,read_buf);
write(c_fd,"i get msgent",128);
return 0;
}
客户端代码
#include<stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
//#include<linux/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int c_fd;
char read_buf[128];
char *msg="asg from client";
//1 socket
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof(struct sockaddr_in));
c_fd=socket(AF_INET, SOCK_STREAM,0);
if(c_fd<0)
{
perror("socket");
exit(-1);
}
c_addr.sin_family=AF_INET;
c_addr.sin_port=htons(6868);
inet_aton("192.168.1.11",&c_addr.sin_addr);
//2 connect
if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in))==-1)
{
perror("connect");
exit(-1);
}
//3 write
write(c_fd,msg,strlen(msg));
//4 read
int n_read=read(c_fd,read_buf,sizeof(read_buf));
printf("readnuf from server:%s\n",read_buf);
return 0;
}