网络编程和套接字

目录

1、网络编程和套接字概要

2、构建电话套接字

2.1:socket函数(安装电话机)

2.2:bind函数(分配电话号码)

2.3:listen函数(连接电话线)

2.4、accept函数(拿起话筒)

3、编写服务器和客户端


1、网络编程和套接字概要

      网络编程就是编写程序使两台联网的计算机相互交换数据。这就是网络编程,是不是非常简单

如今大部分计算机都已经连接到互联网上了,我们只需要考虑如何编写数据传输软件,但这其实也不难,因为操作系统会提供“套接字”(socket)的软件。为了与远程计算机进行数据传输,我们需要连接到互联网上,而编程中的“套接字”就是用来连接该网络的工具。

2、构建电话套接字

       套接字大致分为两种,其中,先要讨论的TCP套接字可以比喻为电话机,那么我们用一个电话机来模拟TCP通信

2.1:socket函数(安装电话机)

   “接电话需要准备什么?”

  “当然是电话机了”

socket函数的功能就好比安装电话机,有了电话机才能通信,我们在Linux系统中调出socket函数的解释文件:

/*需要包含的头文件*/
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
/*
*函数名称:socket
*函数功能:创建一个通信端口
*函数参数:
*    int domain:协议族
*    int type:socket的类型
*    int protocol:协议,一般给0
*函数返回值:int:成功返回socket的文件描述符,失败返回-1
*/
int socket(int domain, int type, int protocol);

domain:
      Name         Purpose                                    Man page
       AF_UNIX      Local communication                        unix(7)
       AF_LOCAL     Synonym for AF_UNIX
       AF_INET      IPv4 Internet protocols                    ip(7)
       AF_AX25      Amateur radio AX.25 protocol               ax25(4)
       AF_IPX       IPX - Novell protocols
       AF_APPLETALK AppleTalk                                  ddp(7)
       AF_X25       ITU-T X.25 / ISO-8208 protocol             x25(7)
       AF_INET6     IPv6 Internet protocols                    ipv6(7)
       AF_DECnet    DECet protocol sockets
       AF_KEY       Key  management protocol, originally de‐
                    veloped for usage with IPsec
       AF_NETLINK   Kernel user interface device               netlink(7)
       AF_PACKET    Low-level packet interface                 packet(7)
       AF_RDS       Reliable Datagram Sockets (RDS) protocol   rds(7)
                                                               rds-rdma(7)
       AF_PPPOX     Generic PPP transport layer, for setting
                    up L2 tunnels (L2TP and PPPoE)
       AF_LLC       Logical  link  control  (IEEE 802.2 LLC)
                    protocol
       AF_IB        InfiniBand native addressing
       AF_MPLS      Multiprotocol Label Switching
       AF_CAN       Controller Area Network  automotive  bus
                    protocol
       AF_TIPC      TIPC, "cluster domain sockets" protocol
       AF_BLUETOOTH Bluetooth low-level socket protocol
       AF_ALG       Interface to kernel crypto API
       AF_VSOCK     VSOCK   (originally  "VMWare  VSockets")   vsock(7)
                    protocol for hypervisor-guest communica‐
                    tion
       AF_KCM       KCM  (kernel connection multiplexor) in‐
                    terface
       AF_XDP       XDP (express data path) interface


type:
         SOCK_STREAM     Provides sequenced, reliable, two-way, connection-based byte streams.  An out-of-band data transmission mechanism may be supported.

       SOCK_DGRAM      Supports datagrams (connectionless, unreliable messages of a fixed maximum length).

       SOCK_SEQPACKET  Provides a sequenced, reliable, two-way connection-based data transmission path for datagrams of fixed maximum length; a consumer is required to read  an
                       entire packet with each input system call.

       SOCK_RAW        Provides raw network protocol access.

       SOCK_RDM        Provides a reliable datagram layer that does not guarantee ordering.

       SOCK_PACKET     Obsolete and should not be used in new programs; see packet(7)

2.2:bind函数(分配电话号码)

问   ”请问您的电话号码是多少?”

答   “我的电话号码是123-21334”

所以bind函数就像给电话机分配电话号一样,给socket函数绑定IP。我们同样从Linux系统中调出bind函数的解释文件,我在其中加了注释,大家可以看一下

 /*需要包含的头文件*/
 #include <sys/types.h>          /* See NOTES */
 #include <sys/socket.h>
 /*
*函数名称:bind
*函数功能:给socket绑定一个IP地址和端口号,让对端能够找到
*函数参数:
*    int sockfd:socket的文件描述符
*    const struct sockaddr *addr:存储地址信息的结构首地址
*    socklen_t addrlen:地址结构所占的字节数
*函数返回值:int:成功返回0,失败返回-1
*/
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
       

2.3:listen函数(连接电话线)

那么你要给对方打电话,那肯定需要一根电话线你们才能互相交流把,所以宾果很对,listen函数就是我们的电话线。

       /*需要包含的头文件*/
       #include <sys/types.h>          /* See NOTES */
       #include <sys/socket.h>
       /*
*函数名称:listen
*函数功能:初始化监听队列
*函数参数:
*    int socket:监听套接字的文件描述符
*    int backlog:监听队列的容量,一般设置为5
*函数返回值:int,成功返回0,失败返回-1
*/
       int listen(int sockfd, int backlog);

2.4、accept函数(拿起话筒)

当你家的电话响了,你的第一个动作是不是去拿起话筒,而在你拿起话筒的时候,你也就跟对方建立齐了连接,那么accept函数也是如此,我们把accept函数的解释性文件拿过来

/*需要包含的头文件*/
       #include <sys/types.h>          /* See NOTES */
       #include <sys/socket.h>
       /*
*函数名:accept
*函数功能:接收客户端的连接请求
*函数参数:
*    int socket:监听套接字的文件描述符
*    struct sockaddr *addr:用来存储对端地址信息的结构的首地址
*    socklen_t *addrlen:存储地址信息结构长度的变量的地址
*函数返回值:int:成功返回通信套接字的文件描述符,失败返回-1
*/
       int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

3、编写服务器和客户端

 那么我们来实战一下,我们来熟悉一下服务器端和客户端的编写流程,那我先把流程给大家展示一下,然后我们就可以照着流程来写程序了

服务器:

   

socket

bind

listen

accept

send/recv

close

 

客户端:

socket

connect

send/recv

close

是不是非常简单?那我们来编写一下吧,当然了哦,我们的程序是在Linux下跑的啊,

//服务器端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

void error_handling(char *message);

int main(int argc,char *argv[])
{
	int serv_sock;
	int clnt_sock;
	struct sockaddr_in serv_addr;
	struct sockaddr_in clnt_addr;
	socklen_t clnt_addr_size;

	char message[]="hello world";

	if(argc !=2)
	{
		printf("Usage:%s <port>\n",argv[0]);
		exit(1);
	}
	
	serv_sock=socket(PF_INET,SOCK_STREAM,0);
	if(serv_sock==-1)
	{
		error_handling("socket() error");
	}
	memset(&serv_addr,0,sizeof(serv_addr));
	serv_addr.sin_family=AF_INET;
	serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
	serv_addr.sin_port=htons(atoi(argv[1]));

	int ret=-1;
	ret=bind(serv_sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
	if(ret==-1)
	{
		error_handling("bind() error");
	}

	ret=listen(serv_sock,5);
	if(ret==-1)
	{
		error_handling("listen() error");
	}
	
	clnt_addr_size=sizeof(clnt_addr);
	clnt_sock=accept(serv_sock,(struct sockaddr *)&clnt_addr,&clnt_addr_size);
	if(clnt_sock <0)
	{
		error_handling("accept error");
	}

	write(clnt_sock,message,sizeof(message));
	close(clnt_sock);
	close(serv_sock);
	return 0;
}

void error_handling(char *message)
{
	fputs(message,stderr);
	fputc('\n',stderr);
	exit(1);
}

//客户端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
void error_handling(char *message);

int main(int argc,char* argv[])
{
	int sock;
	struct sockaddr_in serv_addr;
	char message[30];
	int str_len;

	if(argc!=3)
	{
		printf("Usage:%s <IP><port>\n",argv[0]);
		exit(1);
	}

	sock=socket(PF_INET,SOCK_STREAM,0);
	if(sock==-1)
	{
		error_handling("socket() error");
	}
	memset(&serv_addr,0,sizeof(serv_addr));
	serv_addr.sin_family=AF_INET;
	serv_addr.sin_addr.s_addr=inet_addr(argv[1]);
	serv_addr.sin_port=htons(atoi(argv[2]));

	int ret=-1;
	ret=connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
	if(ret<0)
	{
		error_handling("connect() error");
	}
	str_len=read(sock,message,sizeof(message)-1);
	if(str_len==-1)
	{
		error_handling("read() error");
	}
	puts(message);
	close(sock);
	return 0;
}

void error_handling(char *message)
{
	fputs(message,stderr);
	fputc('\n',stderr);
	exit(-1);
}

        


版权声明:本文为m0_59700590原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。