Linux下的Socket通信

目录

1、Socket服务器与客户端的开发步骤:

2、基本函数原型

2.1socket()函数

2.2bind函数

2.3listen()函数 

2.4accept()函数

2.5connect()函数:

3、代码示例,客户端与服务端实现聊天通信


1、Socket服务器与客户端的开发步骤:

2、基本函数原型

2.1socket()函数

int  socket(int domain, int type, int protocol);//返回sockfd
  • domain:

协议域,又称协议族,指明所使用的的协议族,通常用AF_INET(IPV4),表示互联网协议族(TCP/IP协议族)

  • type参数指定socket类型 :

SOCK_STREAM:

流式套接字提供可靠的、面向连接的通信流;它使用TCP协议,从而保证了数据传输的正确性和顺序性。

SOCK_DGRAM::

数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证是可靠的、无差错的,它使用数据报协议UDP。

SOCK_RAW:

允许程序使用低层协议,原始套接字允许对底层协议如IP或ICMP进行直接访问,功能强大,但使用较为不便,主要用于一些协议的开发。

  • protocol:

故名思意,就是指定协议。通常赋值为0。

0:选择type类型对应的默认协议;

IPPROTO_TCP:TCP传输协议

IPPTOTO_UDP:UDP传输协议

IPPROTO_SCTP:STCP传输协议

IPPROTO_TIPC:TIPC传输协议

2.2bind函数

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

功能:用于绑定IP地址和端口号到socketfd

  • sockfd:

是一个socket的描述符。

  • addr:

一个const struct sockaddr *指针,指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket时的地址协议族的不同而不同,

  • addrlen:

地址长度。

通用函数类型:

struct sockaddr{
  sa_family_t  sa_family;
  char         sa_data[14];
}

(同等替换)ipv4对应的是:

struct sockaddr_in {
    sa_family_t    sin_family; /* address family: AF_INET */
    in_port_t      sin_port;   /* port in network byte order 2字节*/
    struct in_addr sin_addr;   /* internet address 4字节*/
  unsigned char sin_zero[8];
};
/* Internet address. */
struct in_addr {
    uint32_t       s_addr;     /* address in network byte order */
};

ipv6对应的是:

struct sockaddr_in6 { 
    sa_family_t     sin6_family;   /* AF_INET6 */ 
    in_port_t       sin6_port;     /* port number */ 
    uint32_t        sin6_flowinfo; /* IPv6 flow information */ 
    struct in6_addr sin6_addr;     /* IPv6 address */ 
    uint32_t        sin6_scope_id; /* Scope ID (new in 2.4) */ 
};
struct in6_addr { 
    unsigned char   s6_addr[16];   /* IPv6 address */ 
};

 Unix域对应的是:

#define UNIX_PATH_MAX    108
struct sockaddr_un { 
    sa_family_t sun_family;               /* AF_UNIX */ 
    char        sun_path[UNIX_PATH_MAX];  /* pathname */ 
};

地址转换API:

int inet_aton(const char *straddr,struct in_addr *addrp);

功能:将字符串形式的IP地址转化为网络能识别的格式

char* inet_ntoa(struct in_addr inaddr);

功能:把网络格式的ip地址转换为字符串形式

字节序转换API:

#include <netinet/n.h>

uint16_t htons(uint16_t host16bitvalue);//返回网络字节序的值
uint32_t htonl(uint32_t host32bitvalue);//返回网络字节序的值
uint16_t ntohs(uint16_t net16bitvalue);//返回主机字节序的值
uint32_t ntohl(uint32_t net32bitvalue);//返回主机字节序的值

h表示host,n表示net,s表示short(两个字节),l表示long(四个字节),通过上面四个函数,
可以实现主机字节序与网络字节序之间的转换。有时候可以用INADDR_ANY,INADDR_ANY指定地址
让操作系统自己获取。

2.3listen()函数 

int listen(int sockfd, int backlog);

listen函数的第一个参数即为要监听的socket描述字,第二个参数为相应socket可以排队的最大连接个数。

2.4accept()函数

 int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); //返回连接connect_fd

TCP服务器端依次调用socket()、bind()、listen()之后,就会监听指定的socket地址了。TCP客户端依次调用socket()、connect()之后就向TCP服务器发送了一个连接请求。

  • sockfd:

socket服务端的socket描述符。

  • addr:

用来返回已经连接的对端(客户端)的协议地址。

  • addrlen:

客户端地址的长度。

2.5connect()函数:

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

客户机连接主机。用于绑定之后的client端(客户端),与服务器建立连接。

sockfd:

客户端的socket描述符。

addr:

是服务器端的IP地址和端口号的地址结构指针。

addrlen:

地址长度。

3、代码示例,客户端与服务端实现聊天通信

serve.c

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdlib.h>
//#include <linux/in.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <string.h>

int main(int argc,char **argv)
{
	int s_fd;
	int c_fd;
	int clen;
	int n_read;
	char readbuf[128];
	//char *msg = "I have connected";
	char msg[128] = {0};
	struct sockaddr_in s_addr;
	struct sockaddr_in c_addr;
	
	if(argc != 3){
		printf("param is not good\n");
		exit(-1);
	}
	
	memset(&s_addr,0,sizeof(struct sockaddr_in));
	memset(&c_addr,0,sizeof(struct sockaddr_in));

	//1.socket   int socket(int domain, int type, int protocol);
	s_fd = socket(AF_INET,SOCK_STREAM,0);
	if(s_fd == -1){
		perror("socket");
		exit(-1);
	}
	//2.bind 
//	 int bind(int sockfd, const struct sockaddr *addr,
//                socklen_t addrlen);          
	s_addr.sin_family = AF_INET;
	s_addr.sin_port = htons(atoi(argv[2]));
	inet_aton(argv[1],&s_addr.sin_addr);	

	bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));

	//3.listen    int listen(int sockfd, int backlog);
	listen(s_fd,10);
	//4.accept    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
	while(1){
		clen = sizeof(struct sockaddr_in);
		c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);
		if(c_fd == -1){
			perror("accept");
		}

		printf("get connect:%s\n",inet_ntoa(c_addr.sin_addr));
		//5.read
		if(fork() == 0){
			if(fork() == 0){
				while(1){
					memset(msg,0,sizeof(msg));
					printf("input: ");
					fgets(msg,128,stdin);
					msg[strlen(msg)-1]='\0';
					write(c_fd,msg,strlen(msg));	
				}
			}
			while(1){
				memset(readbuf,0,sizeof(readbuf));
				n_read = read(c_fd,readbuf,128);
				if(n_read == -1){
					perror("read");
				}else{
					printf("read messege is:%d,%s\n",n_read,readbuf);
				}
			}
		}
	}
	return 0;
}

client.c

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <stdlib.h>
//#include <linux/in.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <string.h>

int main(int argc,char **argv)
{
	int c_fd;
	int n_read;
	char readbuf[128];
	//char *msg = "msg from client";
	char msg[128] = {0};
	struct sockaddr_in c_addr;
	
	if(argc != 3){
		printf("param is not good\n");
		exit(-1);
	}
	
	memset(&c_addr,0,sizeof(struct sockaddr_in));

	//1.socket   int socket(int domain, int type, int protocol);
	c_fd = socket(AF_INET,SOCK_STREAM,0);
	if(c_fd == -1){
		perror("socket");
		exit(-1);
	}
	//2.connect int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen); 
	c_addr.sin_family = AF_INET;
	c_addr.sin_port = htons(atoi(argv[2]));
	inet_aton(argv[1],&c_addr.sin_addr);	

	if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in)) == -1){
		perror("connect");
		exit(-1);
	}
	//3.write
	while(1){
		if(fork() == 0){
			while(1){
				memset(msg,0,sizeof(msg));
				printf("input: ");
				fgets(msg,128,stdin);
				msg[strlen(msg)-1]='\0';
				write(c_fd,msg,strlen(msg));
			}
		}	
		//4.read
		while(1){
			memset(readbuf,0,sizeof(readbuf));
			n_read = read(c_fd,readbuf,128);
			if(n_read == -1){
				perror("read");
			}else{
				printf("read messege is:%d,%s\n",n_read,readbuf);
			}
		}
	}
	return 0;
}

 

 

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值