Socket通讯示例

一 最简例程实现socket网络传输

  1. 服务器端( 比客户端先运行)
    vi socket_server.c
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <errno.h>
  4 #include <string.h>
  5 #include <sys/types.h>
  6 #include <netinet/in.h>
  7 #include <sys/socket.h>
  8 #include <sys/wait.h>
  9 #include <arpa/inet.h>
 10 #include <signal.h>
 11 
 12 #define SERVPORT    3333    /* port */
    /*系统默认值队列大小为5*/
 13 #define BACKLOG     5       /* max client connet queue*/
 14 
 15 int main ()
 16 {
 17     int server_sockfd,client_sockfd;
 18     int server_len,client_len;
 19     struct sockaddr_in server_address,client_address;
 20 
 21     server_sockfd = socket(AF_INET,SOCK_STREAM,0);
 22     server_address.sin_family = AF_INET;
 23     server_address.sin_port = htons(SERVPORT);
        /* INADDR_ANY 表示服务器所有的网卡IP都监听*/
 24     server_address.sin_addr.s_addr = INADDR_ANY;
 25     bzero(&(server_address.sin_zero),8);
 26 
 27     server_len = sizeof(server_address);
 28 
 29     bind(server_sockfd,(struct sockaddr *)&server_address,server_len);
 30     listen(server_sockfd, BACKLOG);
        /* 忽略子进程停止或结束信号 */
 31     signal(SIGCHLD,SIG_IGN);
 32     while(1) {
 33         int ch;
 34         client_len = sizeof(client_address);
 35         printf("wait client connet ...\n");
            /* 收不到client connect 请求,则一直阻塞等待 */
 36         client_sockfd = accept(server_sockfd,(struct sockaddr *)&client_address,&client_len);
 37         printf("accept a client connet \n");
 38         if(fork() == 0) {
 39             read(client_sockfd,&ch,sizeof(ch));
 40 //          sleep(5);
 41             ch++;
 42             write(client_sockfd,&ch,sizeof(ch));
 43             close(client_sockfd);
 44             exit(0);
 45         } else {
 46             close(client_sockfd);
 47         }
 48     }
 49 }
  1. 客户端
    vi socket_client.c
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 #include <string.h>
  5 #include <sys/types.h>
  6 #include <netinet/in.h>
  7 #include <sys/socket.h>
  8 
  9 #define SERVPORT    3333
 10 
 11 int main () {
 12     int clientfd;
 13     struct sockaddr_in server_address;
 14 
 15     clientfd = socket(AF_INET,SOCK_STREAM,0);
 16     if (clientfd == -1) {
 17         printf("socketfd get faild! \n");
 18         exit(0);
 19     }
 20     server_address.sin_family = AF_INET;
 21     server_address.sin_port = htons(SERVPORT);
        /* 远程服务器 IP */
 22     server_address.sin_addr.s_addr = inet_addr("192.168.2.167");
 23     bzero(&(server_address.sin_zero),8);
 24 
 25     if(connect(clientfd,(struct sockaddr *)&server_address,sizeof(struct sockaddr)) == -1) {
 26         printf("connect error !\n");
 27         exit(1);
 28     }
 29 
 30     int data;
 31 
 32     write(clientfd,&data,sizeof(data));
 33     printf("write %d\n",data);
 34     read(clientfd,&data,sizeof(data));
 35     printf("read %d\n",data);
 36     sleep(2);
 37 
 38     close(clientfd);
 39 }

二 所涉及到的函数名词解释

1. include文件
	○ #include <netdb.h>      /* gai_strerror */
	○ #include <sys/socket.h>
2. Socket是什么?
	a. Socket是应用层与TCP/IP协议族通讯的中间软件抽象层,它是一组接口
	User Process
	Socket
	TCP/UDP
	IP
	Ethernet
3. Socket的基本函数
	○ socket  (服务器/客户端)返回一个socket描述符(类似于open函数)
		§ int socket(int domain,int type,int protocol)
			□ domain:协议族(family),常用AF_INET(32位ipv4+16位port),AF_INET6
			□ type:socket类型,常用SOCK_STREAM(TCP)、SOCK_DGRAM(UDP)
			□ protocol:协议,常用IPPROTO_TCP、IPPTORO_UDP
	○ bind 服务器绑定到指定地址
		§ int bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen)
			□ sockfd:即socket描述符(socket函数返回值)
			□ addr:指向要绑定给sockfd的协议地址(ipv4与ipv6不同)
			□ addrlen:对应地址长度
	○ listen服务器监听
		§ int listen(int sockfd,int backlog)
			□ 函数作用:将套接字(sockfd)变成被动的连接监听套接字(被动等待客户端的连接),并且将该套接字和套接字对应的连接队列长度告诉Linux内核。
			□ backlog:为相应socket可以排队的最大连接个数(未完成连接队列+已完成连接队列),默认值为5
	○ connect客户端请求连接
		§ int connect(int sockfd,const struct sockaddr *addr,socklen_t addrlen)
			□ addr:为服务器的socket地址
	○ accept服务器阻塞等待client连接
		§ int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen)
			□ 从处于established状态的连接队列头部取出一个已完成的连接(client connet 成功),如果这个队列没有已经完成的连接,accept()函数就会阻塞。TCP的连接队列满后,Linux不会如书中所说的拒绝连接,只是有些会延时连接。
			□ sockfd:为服务器的socket描述字
			□ addr:用于返回客户端的协议地址
			□ *addrlen:&对应地址长度
			□ 返回值:是内核自动生成的一个全新的描述字,代表与client的TCP连接
		§ 服务器仅仅只创建一个监听socket描述字,而为每个连接客户创建一个已连接socket描述字,服务结束则关闭。
	○ read、write(服务器/客户端)数据传输
		§ ssize_t read(int fd,void *buf,size_t count)
		§ ssize_t write(int fd,const void *buf,size_t count)
		§ ssize_t sendto(int sockfd,const void *buf,size_t len,int flags,const struct sockaddr *dest_addr,socklen_t addrlen)
			□ buf:数据报缓存地址
			□ len:数据报长度
			□ flags:指定发送形式,一般为0
			□ dest_addr:目的的套接字地址
			□ addrlen:所指地址的长度
			□ 返回值:已发送的字节数
		§ ssize_t recvfrom(int sockfd,void *buf,size_t len,int flags,struct sockaddr *src_addr,socklen_t *addrlen)
	○ close(服务器/客户端)关闭socketfd
		§ int close(int fd)
			□ 完成了连接后的读写操作,就要关闭相应的socket描述字
4. 相关函数
	○ getaddrinfo 将主机和服务转换到socket地址
		§ int getaddrinfo(const char *restrict nodename,const char *restrict servname,const  struct addrinfo **restrict hints,struct addrinfo **restrict res)
			□ nodename:host或者IP地址,作为服务可为空
			□ servname:十进制端口号或服务名称ftp,http
			□ hints:获取信息要求设置
			□ res:获取信息结果
			□ 返回值:返回一个addrinfo结构体由套接字函数直接使用
	○ freeaddrinfo 
		§ void freeaddrinfo(struct addrinfo *ai)
	○ getnameinfo 将socket地址转换到主机和服务
		§ int getnameinfo(const struct sockaddr *sa,socklen_t salen,char *host,size_t hostlen,char *serv,size_t servlen,int flags)
	○ 地址转换
		§  int inet_aton(const char *cp, struct in_addr *inp)  字符串转32整数表示
		§ char *inet_ntoa(struct in_addr in)  整数转字符串
	○ 网络字节序统一采用 big endian 先传低字节
		§ 从主机转网络序
			□ htons(unsigned short)
			□ htonl (unsigned long)
				® h:host 本地主机
				® to:
				® n:net网络的意思
				® l: unsigned long
		§ 从网络序转换到主机序 
			□ ntohs (unsigned short)
			□ ntohl(unsigned long)
		§ 网络中标识一台主机可以用IP地址 ,也可用主机名
			□ struct hostent *gethostbyname( const char  *hostname)

Program Flow Chart 模型图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值