socket/tcp协议
协议:
计算机网络中实现通信必须有一定的约定,速率、传输代码、代码结构、传输控制步骤和出错控制等约定,约定称为通信协议。
在两个节点之间要成功的通信,两个节点之间必须约定使用共同的语言,这些被通信各方共同遵守的约定、语言、规则被称为协议。
在internet中,最为通用的网络协议是TCP/IP协议。
OSI七层模型:
应用、表示、会话、传输、网络、数据链路、物理。
TCP/IP四层模型:
应用、传输、网络、物理+数据链路。
TCP/IP实际上是一个一起工作的通信家族,为网络数据通信提供通路。
TCP/IP协议簇为三个部分:
internet协议(IP)
传输控制协议(TCP)和用户数据报文协议(UDP)
处于TCP和UDP之上的一组协议专门开发的应用程序。远程登录(TELNET)、文件传输协议(FTP)、域名服务(DNS)和简单的邮件传送程序(SMTP)等许多协议。
//more /etc/services 查看端口绑定信息。
完整socket:协议、本地地址、本地端口、远程地址、远程端口。
#include<sys/socket.h>
int socket(int domain,int type,int protocal)
返回:成功返回描述符,出错返回-1.
socket创建在内核中,若创建成功返回内核文件描述表中的socket描述符。实际上就是一个结构体。
domin:
AF_INET IPv4网域
AF_INET6 IPv6网域
AF_UNIX nuix域
AF_UNSPEC 未指定
protocol:
通常为0,表示按给定的域和套接字类型选择默认协议。
type:
SOCK_STREAM
流式的套接字可以提供可靠的、面向连接的通讯流,它使用了TCP协议,TCP保证了数据传输的正确性和顺序性。
SOCK_DGRAM
数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠,无差错。使用数据报协议UDP协议。
SOCK_RAW
原始套接字允许对底层协议如IP或者ICMP直接访问,主要用于新的网络协议实现的测试等。
SOCK_SEQPACKET
长度固定、有序、可靠的面向连接报文传递。
网络传输的数据一定要统一顺序,所以对于内部字节表示顺序和网络字节顺序不同的机器,就一定要对数据进行转换。
uint32_t htonl(uint32_t hostlong)
将一个32位整数由主机字节序转换成网络字节序。
uint32_t htons(uint16_t hostlong)
将一个16位整数由主机字节序转换成网络字节序。
uint32_t ntohl(uint32_t hostlong)
将一个32位整数由网络字节序转换成主机字节序。
uint32_t ntohs(uint32_t hostlong)
将一个16位整数由网络字节序转换成主机字节序。
tcp服务器端:
/*************************************************************************
> File Name: tcp_server.c
> Author: CC
> Mail: [email protected]
> Created Time: 2018年10月21日 星期日 15时26分42秒
************************************************************************/
#include<arpa/inet.h>
#include<stdio.h>
#include<netdb.h>
#include<sys/socket.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<memory.h>
#include<signal.h>
#include<time.h>
int sockfd;
void sig_handler(int signo){
if(signo == SIGINT){
printf(" service close \n");
close(sockfd);
exit(1);
}
}
//out client something
void out_addr(struct sockaddr_in *clientaddr)
{
int port = ntohs(clientaddr->sin_port);
char ip[16];
memset(ip,0,sizeof(ip));
//ip 从网络字节序转换成点分十进制
inet_ntop(AF_INET,&clientaddr->sin_addr.s_addr,ip,sizeof(ip));
printf("client: %s(%d) connected\n",ip,port);
}
void do_service(int fd)
{
//获得系统时间
long t = time(0);
char *s = ctime(&t);
size_t size = strlen(s) * sizeof(char);
//服务器时间写回到客户端
if(write(fd,s,size) != size){
perror("write error!\n");
exit(1);
}
}
int main(int argc,char *argv[])
{
if(argc < 2){
printf("usage: %s #port\n",argv[0]);
exit(1);
}
if(signal(SIGINT,sig_handler) == SIG_ERR){
perror("signal sigint error");
exit(1);
}
//创建socket,kernel,struct
//AF_INET:ipv4
//SOCK_STREAM:tcp协议
//creat
sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd < 0){
perror("socket error!\n");
exit(1);
}
//bind
//地址,端口设定后绑定
struct sockaddr_in serveraddr;
memset(&serveraddr,0,sizeof(serveraddr));
//地址中填入ip,port,internet地址簇
serveraddr.sin_family = AF_INET;//ipv4
serveraddr.sin_port = htons(atoi(argv[1]));//端口
// serveraddr.sin_addr.s_addr = "192.168.0.10";//指定单一地址相应
serveraddr.sin_addr.s_addr = INADDR_ANY;//响应所有地址
if(bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr)) < 0){
perror("bind error");
exit(1);
}
//listen
//通知操作系统去接受来自客户端的链接请求
//讲请求放置到10的大小队列当中
if(listen(sockfd,10) < 0){
perror("listen error");
exit(1);
}
//accept
//从队列中获得一个客户端的链接请求
//若没有链接,则阻塞
struct sockaddr_in clientaddr;
socklen_t clientaddr_len = sizeof(clientaddr);
while(1){
int fd = accept(sockfd,(struct sockaddr*)&clientaddr,&clientaddr_len);
if(fd < 0){
perror("accept error!\n");
continue;
}
//read write
out_addr(&clientaddr);
do_service(fd);
//close
close(fd);
return 0;
}
}
tcp客户端:
/*************************************************************************
> File Name: tcp_client.c
> Author: CC
> Mail: [email protected]
> Created Time: 2018年10月21日 星期日 16时56分56秒
************************************************************************/
#include<arpa/inet.h>
#include<unistd.h>
#include<stdio.h>
#include<netdb.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<string.h>
#include<memory.h>
int main(int argc,char *argv[])
{
if(argc < 3){
printf("Usage : %s ip port \n",argv[0]);
exit(1);
}
//创建
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd < 0){
perror("socket ceart error!\n");
exit(1);
}
//connect
struct sockaddr_in serveraddr;
memset(&serveraddr,0,sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[2]));
//将ip地址转换成网络字节序
inet_pton(AF_INET,argv[1],&serveraddr.sin_addr.s_addr);
if(connect(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr)) < 0){
perror("connect error!\n");
exit(1);
}
//read write
char buffer[1024];
memset(buffer,0,sizeof(buffer));
size_t size;
if((size = read(sockfd,buffer,sizeof(buffer))) < 0){
perror("read error!\n");
exit(1);
}
if(write(STDOUT_FILENO,buffer,size) != size){
perror("writr error!");
}
close(sockfd);
return 0;
}
上一篇: 线性表之【按值查找并返回其位序】
下一篇: 逗男逗女很会逗笑!