欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

socket/tcp协议

程序员文章站 2022-03-15 21:05:25
...

        协议:
        计算机网络中实现通信必须有一定的约定,速率、传输代码、代码结构、传输控制步骤和出错控制等约定,约定称为通信协议。
        在两个节点之间要成功的通信,两个节点之间必须约定使用共同的语言,这些被通信各方共同遵守的约定、语言、规则被称为协议。
        在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;
}

 

相关标签: tcp