socket编程——TCP

函数流程框图:


创建:

int  socket(int  domain,int  type,int  protocol);

domain——>协议域:

AF_INET————IPV4。

AF_INET6————IPV6。

AF_LOCAL————Unix域。

type——>类型:

SOCK_STREAM——流式套接字,TCP协议支持该套接字(提供面向连接,可靠的数据传输服务,数据按字节流,按顺序收发,保证在传输过程中无丢失,无冗余)。

SPCK_DGRAM———数据报套接字,UDP协议支持该套接字(提供面向无连接的服务,数据收发无序,不能保证数据的准确到达)。

SOCK_RAM————原始套接字,常用于检测新协议。允许对低于传输层的协议或物理网络直接访问。

protocol——>协议:

0————自动根据type匹配协议。

IPPROTO_TCP。

IPPROTO_UDP。

返回值:

>0时为socket描述符;-1为失败。

关闭:

int  close(int  fd);

int  shutdown(int sockfd,int howto);

sockfd——socket套接字。

howto:

SHUT_RD———值为0;关闭连接的读。

SHUT_WR———值为1;关闭连接的写。

SHUT_RDWR——值为2;连接的读和写都关闭。

绑定:

int  bind(int  socket,const struct sockaddr* address,socklen_t address_len);

socket—————套接字描述符。

address—————地址和端口号。

address_len———address缓冲区的长度。

返回值——————0为成功;SOCKET_ERROR为失败。

监听:

int listen(int sockfd,int backlog);

socket—————监听的socket描述符。

backlog————排队的最大连接个数。

返回值—————0为成功;-1为失败。

连接:

int connect(int sockfd,const struct sockaddr* addr,socklen_t,addrlen);

sockfd————客户端的socket描述符。

addr—————服务器的socket地址。

addrlen————服务器的socket地址的长度。

返回值—————0为成功l-1为失败。

接受:

int accept(int sockfd,struct socketaddr* addr,socklen_t* addrlen);

sockfd————服务器的socket描述符,或,监听socket描述符。

addr—————客户端的socket地址。

addrlen————客户端的socket地址长度。

返回值————非-1为连接描述符;-1为失败。

发送:

ssize_t write(int fd,const void* buf,size_t len);

fd————文件描述符。

buf————写入的数据。

len————写入数据长度。

返回值———>0为实际所写的字节数;<0出错。

ssize_t  send(int sockfd,const void* buf,size_t len,int flags);

flags——通常为0。

返回值及其他——同上。

ssize_t sendto(int sockdf,const void* buf,size_t len,int flags,const struct sockaddr* dest_addr,socklen_t addrlen);

dest_addr———目标socket地址。

addrlen————目标socket地址长度。

返回值及其他——同上。

接收:

ssize_t read(int fd,void* buf,size_t len);

buf————读取文件。

返回值——0为读到文件的结束;>0实际所读到的字节数;<0出错。

ssize_t recv(int sockfd,void* buf,size_t len,int flags);

flags——————通常为0。

返回值及其他——同上。

ssize_t recvfrom(int sockdf,void* buf,size_t len,int flags,const struct sockaddr* src_addr,socklen_t addrlen);

src_addr————目标socket地址。
addrlen—————目标socket地址长度。
返回值及其他——同上。

结构体:

struct sockaddr:

struct sockaddr {
    unsigned short sa_family;
    char sa_data[14];
};

struct sockaddr_in:

struct sockaddr_in{
    short sin_family;
    unsigned short sin_port;
    struct in_addr sin_addr;
    unsigned char sin_zero[8];
};

struct in_addr:

struct in_addr {
    in_addr_t s_addr;
};

in_addr_t:

typedef unsigned int in_addr_t;

struct sockaddr_in6(IPV6):

struct sockaddr_in6{
   //IPv6 为固定的24 字节长度
   uint8_t sin6_len; 
   //地址簇类型,为AF_INET6
   sa_family_t sin6_family;
   //16 位端口号,网络字节序
   in_port_t sin6_port;
   //32 位流标签
   uint32_t sin6_flowinfo;
   //128 位IP 地址
   struct in6_addr sin6_addr;
}

特殊地址设置:

通配地址(0.0.0.0):

主机上所有IP,多网卡并用。
ipv4:
in_addr.sin_addr.s_addr = htonl(INADDR_ANY);
ipv6:
in6_addr.sin6_addr = in6addr_any;

回环地址(127.0.0.1):

本地虚拟接口,无网卡可用,也不需要网卡。用于检查本地网络协议。
ipv4:
in_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
ipv6:
in6_addr.sin6_addr = in6addr_loopback;

广播地址:

受限广播地址——255.255.255.255
子网广播地址——xxx.xxx.xxx.255
全子网广播———xxx.xxx.255.255
ipv4:
in_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
ipv6:
无。

代码:

tcp_cliect:

#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>

void show_info(int connfd){
	struct sockaddr_in local_addr;
	bzero(&local_addr,sizeof(local_addr));
	socklen_t local_addr_len = sizeof(local_addr);
	getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len);
	printf("client local %s:%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));
	
	struct sockaddr_in peer_addr;
	bzero(&peer_addr,sizeof(peer_addr));
	socklen_t peer_addr_len = sizeof(peer_addr);
	getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len);
	printf("clinet peer %s:%d\n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));
}
int main(int argc,char* argv[]){
	if(4 != argc){
		printf("usage:%s <ip> <#port> <message>\n",argv[0]);
		return 1;
	}

	int connfd = socket(AF_INET,SOCK_STREAM,0);
	if(-1 == connfd){
		perror("socket err");
		return 1;
	}
	struct sockaddr_in remote_addr;
	bzero(&remote_addr,sizeof(remote_addr));
	remote_addr.sin_family = AF_INET;
	remote_addr.sin_addr.s_addr = inet_addr(argv[1]);
	remote_addr.sin_port = htons(atoi(argv[2]));	
	if(-1 == connect(connfd,(struct sockaddr*)&remote_addr,sizeof(remote_addr))){
		perror("connect err");
		return 1;
	}
	show_info(connfd);
	write(connfd,argv[3],strlen(argv[3])+1);
	printf("client send:%s\n",argv[3]);
	char buf[BUFSIZ];
	bzero(buf,BUFSIZ);
	if(-1 == read(connfd,buf,BUFSIZ)){
		perror("read err");
		return 1;
	}
	printf("client recv:%s\n",buf);
	close(connfd);
}

tcp_server:

#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>

void show_info(int connfd){
	struct sockaddr_in local_addr;
	bzero(&local_addr,sizeof(local_addr));
	socklen_t local_addr_len = sizeof(local_addr);
	getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len);
	printf("server local %s:%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));
	
	struct sockaddr_in peer_addr;
	bzero(&peer_addr,sizeof(peer_addr));
	socklen_t peer_addr_len = sizeof(peer_addr);
	getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len);
	printf("server peer %s:%d\n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));
}
int main(int argc,char* argv[]){
	if(3 != argc){
		printf("usage:%s <ip> <#port>\n",argv[0]);
		return 1;
	}

	int listenfd = socket(AF_INET,SOCK_STREAM,0);
	if(-1 == listenfd){
		perror("listenfd open err");
		return 1;
	}
	printf("socket create OK\n");
	
	int flag = 1;
	setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));	

	struct sockaddr_in local_addr;
	bzero(&local_addr,sizeof(local_addr));
	local_addr.sin_family = AF_INET;
	local_addr.sin_addr.s_addr = inet_addr(argv[1]);
 	local_addr.sin_port = htons(atoi(argv[2]));

	if(-1 == bind(listenfd,(struct sockaddr*)&local_addr,sizeof(local_addr))){
		perror("bind err");
		return 1;
	}
	printf("bind OK\n");

	if(-1 == listen(listenfd,10)){
		perror("listen err");
		return 1;
	}
	printf("listen OK\n");
	struct sockaddr_in remote_addr;
	bzero(&remote_addr,sizeof(remote_addr));
	socklen_t remote_addr_len = sizeof(remote_addr);
	int connfd = accept(listenfd,(struct sockaddr*)&remote_addr,&remote_addr_len);
	if(-1 == connfd){
		perror("accept err");
		return 1;
	}

	show_info(connfd);

	printf("accept %s:%d\n",inet_ntoa(remote_addr.sin_addr),ntohs(remote_addr.sin_port));
	char buf[BUFSIZ];
	bzero(buf,BUFSIZ);
	if(-1 == read(connfd,buf,BUFSIZ-1)){
		perror("read err");
		return 1;
	}
	printf("server recv:%s\n",buf);

	if(-1 == write(connfd,buf,strlen(buf)+1)){
		perror("write err");
		return 1;
	}
	printf("server send:%s\n",buf);	
	close(connfd);
	close(listenfd);

}

结果:


猜你喜欢

转载自blog.csdn.net/lingfeng2019/article/details/73278034