一、各部分功能:
服务器:主动建立服务程序,等待客户端连接,相应客户端的请求
客户端:当有需求时,主动连接服务器,发出服务请求
二、书写顺序:
1、先写服务器程序,然后用telnet 模拟客户端远程登录
2、再写客户端程序,登录写好的服务器
3、最后写客户端和服务器通信的语句。
三、先写服务器程序,然后用telnet 模拟客户端远程登录
1、socket
int socket (int domain, int type, int protocol);
功能:建立socket文件
输入参数:
domain 是地址族
网络通信 填写PF_INET (AF_INET)
本地通信 填写PF_UNIX (AF_UNIX)
type // 套接字类型
SOCK_STREAM // 流式套接字 ---TCP协议
SOCK_DGRAM // 数据报套接字--UDP协议
protocol 参数通常置为0
返回值:成功返回:socket文件描述符
失败返回:-1 并置错误码
socket例子:
int listenfd = 0;
if((listenfd = socket(PF_INET,SOCK_STREAM,0)) == -1)
{
perror("socket");
return -1;
}
2、建立网络地址
网络地址原型:
struct sockaddr_in struct sockaddr_un
{
u_short sin_family; // 地址族, AF_INET,2 bytes
u_short sin_port; // 端口,2 bytes
struct in_addr sin_addr; // IPV4地址,4 bytes
char sin_zero[8]; // 8 bytes unused,作为填充
};
IPv4地址结构
// internet address
struct in_addr
{
in_addr_t s_addr; // u32 network address
};
定义一个struct sockaddr_in类型的变量并清空
struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(serveraddr));
填充地址信息
serveraddr.sin_family = PF_INET;
serveraddr.sin_port = htons(8888);
serveraddr.sin_addr.s_addr = inet_addr(“172.16.7.111”);
3、bind
int bind(int listenfd,struct sockaddr *serveraddr, int addrlen) ;
功能:将创建好的socket文件和一个网络地址进行绑定
输入参数:
listenfd: 调用返回的文件描述符
serveraddr:填充后的地址
addrlen: serveraddr地址结构的长度
返回值:成功:0或 失败返回-1,并错误码
bind例子
if(bind(listenfd, (struct sockaddr*)(&serveraddr), sizeof(serveraddr)) == -1)
{
perror("bind");
return -1;
}
4、listen函数
int listen (int listenfd, int backlog);
功能:将一个普通套接字变为监听套接字,同时设置等待队列最大长度。
输入参数:
listenfd:监听连接的套接字
backlog
指定了正在等待连接的最大队列长度,它的作用在于处理可能同时出现的几个连接请求。
DoS(拒绝服务)攻击即利用了这个原理,非法的连接占用了全部的连接数,造成正常的连接请求被拒绝。
返回值:成功 0 或 失败-1
listen例子:
listen(listenfd, 5);
5、accept函数
int accept(int listenfd, struct sockadd *addr, socklen_t *addrlen) ;
功能:当有客户端连接请求时,建立连接,返回连接套接字
输入参数:
sockfd : 监听套接字 socket_fd
addr : 对方地址
struct sockaddr_in clinet_addr; NULL
bzero(client_addr,sizeof(client_addr));
传参数:(struct sockaddr *)(&client_addr)
addrlen:地址长度
socklen_t len =sizeof(client_addr) NULL
传参数:&len
返回值:已建立好连接的套接字或-1
accept例子:
定义存放客户端地址的变量:
struct sockaddr_in clinet_addr;
bzero(client_addr,sizeof(client_addr));
定义存放客户端地址长度的变量:
socklen_t len =sizeof(client_addr)
定义接受连接套接字的文件描述符变量:
int connect_fd = 0;
if((connect_fd = accept(socket_fd,(struct sockaddr *)(&client_addr),&len) )== -1)
{
perror("accept");
return -1;
}
6、打印客户端地址:
printf("clientaddr-->IP:%s\n",inet_ntoa(clientaddr.sin_addr));
printf("clientaddr-->PORT: %d \n",ntohs(clientaddr.sin_port));
7、close函数
close(socket_fd);
close(connect_fd);
四、再写客户端程序,登录写好的服务器
1、创建socket
2、填充服务器的网络地址
3、connect函数
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
功能:连接服务器
输入参数:
sockfd : socket返回的文件描述符
serv_addr : 服务器端的地址信息?
addrlen : serv_addr的长度
返回值:成功 0 或 失败-1
if(connect(socketfd,(struct sockaddr *)&server_addr,sizeof(server_addr)) == -1)
{
perror("connect");
return -1;
}
五、最后写客户端和服务器通信的语句。
1、在客户端添加发送函数
ssize_t send(int socket, const void *buffer, size_t length, int flags);
功能:发送信息
输入参数:
socket :文件描述符
buffer : 发送缓冲区首地址
length : 发送的字节数
flags : 发送方式(通常为0)
返回值:
成功:实际发送的字节数
失败:-1, 并设置errno
2、在服务器端添加接收函数
ssize_t recv(int socket, const void *buffer, size_t length, int flags);
功能:接收信息
输入参数:
socket:文件描述符
buffer : 发送缓冲区首地址
length : 发送的字节数
flags : 接收方式(通常为0)
返回值:
成功:实际接收的字节数
失败:-1, 并设置errno
注意: socket 是连接套接字