网络编程之套接字TCP

TCP是一种面向连接的、可靠的、基于 IP 的传输层协议。通过 TCP 可以保证我们传送的数据的正确性。
Linux 下网络通信程序基本上都是采用 socket 的方式。socket 起源于 Unix,而 Unix/Linux 基本哲学之
一就是“一切皆文件” ,都可以用“打开 open->读写 read/write->关闭 close”模式来操作。Socket 就是该
模式的一个实现,socket 即是一种特殊的文件,一些 socket 函数就是对其进行的操作(读/写 IO、打开、关
闭) 。说白了 socket 是应用程序与 TCP/IP 协议族通信的中间软件抽象层,它是一组接口。
现在我们看一下基于 TCP/IP 应用程序通信的流程,如下图:

网络编程之套接字TCP_第1张图片

通过上图我们可以看到 TCP/IP 通信是基于服务器/客户端的模式来实现的,首先是服务器(server)端调
用 socket 函数创建一个套接字, 然后调用 bind 绑定函数, 绑定函数主要是设置通信时使用哪种地址族 (IPv4,
IPv6 等) ,使用的端口号。然后调用 listen 函数来监听客户端的连接请求。
现在我们来看下客户端(client)端的流程,首先调用 socket 函数创建一个套接字,然后调用 connect
函数连接服务器,这时服务器端的 listen 函数监听到客户端的连接请求就会调用 accept 函数去接受请求,这
样连接就建立好了。之后双方就可以调用 read/write 函数收发数据了,在完成通信以后服务器(server)和
客户端(client)调用 close 函数关闭创建的套接字。

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

     –socket()函数用于根据指定的地址族、数据类型和协议来分配一个套接口的描述字及其所用的资源 

     –socket(AF_INET, SOCK_STREAM, 0)

     –domain:目前仅支持AF_INET格式,也就是说ARPA Internet地址格式。

     –typetype:新套接口的类型描述,SOCK_STREAM 提供面向连接的稳定数据传输,即TCP协议。

     –protocol:套接口所用的协议。如调用者不想指定,可用0指定,表示缺省。

2、void bzero(void *s, int n);

    –bzero(&s_add,sizeof(struct sockaddr_in))

    –s:要置零的数据的起始地址;

    –n:要置零的数据字节个数。

3、in_addr_t inet_addr(const char *cp)

    –inet_addr(argv[1])

    –inet_addr()的功能是将一个点分十进制的IP转换成一个长整数型数(u_long类型)

4、建立与一个端口的连接

     int connect (int sockfd,struct sockaddr * serv_addr,int addrlen)
     –sockfd:标识一个未连接套接口的描述字
     –serv_addr:套接字想要连接的主机地址和端口号
     –addrlen:缓冲区name的长度

5、绑定

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

     –bind()函数通过给一个未命名套接口分配一个本地名字来为套接口建立本地捆绑(主机地址/端口号)

6、int listen(SOCKET sockfd, int backlog)

    –listen函数使用主动连接套接字变为被连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程。在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。
if(-1 == listen(sfp,5))
    –sockfd 一个已绑定未被连接的套接字描述符
    –backlog  连接请求队列的最大长度

7、int accept(int sockfd, struct sockaddr* addr, socklen_t* len)
    –accept默认会阻塞进程,直到有一个客户连接建立后返回,它返回的是一个新可用的套接字,这个套接字是连接套接字。

8、ssize_t send (int s,const void *msg,size_t len,int flags)
     –send(nfp, buffer, strlen(buffer), 0)
     –s:指定发送端套接字描述符
    –msg:一个存放应用程式要发送数据的缓冲区
    –len:参数指明实际要发送的数据的字节数
    –flags:参数一般置0

    返回:成功发送字节,错误-1

9、把网络也当做文件来理解,直接用read函数
     –read(cfd, buffer, 1024)

   返回:读取的字节数,错误-1
10、同上read的理解方式
    –close(cfd)

例:client.c

 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
int main(int argc, char **argv)
{
	int cfd;
	int recbyte;
	int sin_size;
	char buffer[1024] = {0};

	struct sockaddr_in s_add, c_add;
	unsigned short portnum = 0x8888;

	printf("Hello,welcome to client!\r\n");

	if(argc != 2)
	{
		printf("usage: echo ip\n");
		return -1;
	}

	cfd = socket(AF_INET, SOCK_STREAM, 0);
	if(-1 == cfd)
	{
		printf("socket fail ! \r\n");
		return -1;
	}

	printf("socket ok !\r\n");

	bzero(&s_add,sizeof(struct sockaddr_in));
	s_add.sin_family=AF_INET;
	s_add.sin_addr.s_addr= inet_addr(argv[1]);
	s_add.sin_port=htons(portnum);
	printf("s_addr = %#x ,port : %#x\r\n",s_add.sin_addr.s_addr,s_add.sin_port);

	if(-1 == connect(cfd,(struct sockaddr *)(&s_add), sizeof(struct sockaddr)))
	{
		printf("connect fail !\r\n");
		return -1;
	}

	printf("connect ok !\r\n");

	while(1)
	{
		if(-1 == (recbyte = read(cfd, buffer, 1024)))
		{
			printf("read data fail !\r\n");
			return -1;
		}

		printf("read ok\r\nREC:\r\n");
		buffer[recbyte]='\0';
		printf("%s\r\n",buffer);
	}

	close(cfd);

	return 0;

}


例:server.c

 

 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
int main()
{
	int sfp, nfp, num = 0;
	struct sockaddr_in s_add,c_add;
	int sin_size;
	unsigned short portnum=0x8888;

	char buffer[100] = {0};

	printf("Hello,welcome to my server !\r\n");

	sfp = socket(AF_INET, SOCK_STREAM, 0);
	if(-1 == sfp)
	{
		printf("socket fail ! \r\n");
		return -1;
	}

	printf("socket ok !\r\n");

	bzero(&s_add,sizeof(struct sockaddr_in));
	s_add.sin_family=AF_INET;
	s_add.sin_addr.s_addr=htonl(INADDR_ANY);
	s_add.sin_port=htons(portnum);

	if(-1 == bind(sfp,(struct sockaddr *)(&s_add), sizeof(struct sockaddr)))
	{
		printf("bind fail !\r\n");
		return -1;
	}

	printf("bind ok !\r\n");

	if(-1 == listen(sfp,5))
	{
		printf("listen fail !\r\n");
		return -1;
	}

	printf("listen ok\r\n");



	sin_size = sizeof(struct sockaddr_in);

	nfp = accept(sfp, (struct sockaddr *)(&c_add), &sin_size);
	if(-1 == nfp)
	{
		printf("accept fail !\r\n");
		return -1;
	}

printf("accept ok!\r\nServer start get connect from %#x : %#x\r\n", ntohl(c_add.sin_addr.s_addr), ntohs(c_add.sin_port));
	while(1)
	{
		memset(buffer, 0, 100);
		sprintf(buffer, "hello,welcome to my server(%d) \r\n", num++);
		send(nfp, buffer, strlen(buffer), 0);
		usleep(500000);
	}


	close(nfp);

	close(sfp);

	return 0;
}

 

你可能感兴趣的:(网络编程)