linux学习笔记17-网络通信socket-tcp

套接字(socket)

 socket是跨平台的,可以用在系统间通信(windows/linux/Android/ios等),也可以用在进程间通信,常用socket类型,分为tcp(流式SOCK_STREAM)和udp(数据报文SOCK_DGRAM).概念性的先不讲,先看看在Linux怎么使用吧.

client(tcp客户端实现)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(int argc,char *argv[])
{
	if(argc < 3)                                   //接收3个参数,分别为./sock(程序名) 127.0.0.1(ip地址) 8081(端口号)
	{
		printf("argc < 3\n");
		return -1;
	}
	int port = atoi(argv[2]);
	int sock = socket(AF_INET,SOCK_STREAM,0);     //初始化socket
	struct sockaddr_in addr;                      //ip地址结构
	memset(&addr,0,sizeof(addr));                 //初始化ip结构
	addr.sin_family = AF_INET;                    //设置结构类型类tcp/ip地址
	addr.sin_port = htons(port);                  //指定一个端口号, htons将short类型从host字节类型换net字节类型
	addr.sin_addr.s_addr = inet_addr(argv[1]);    //将ip地址转为int类型数据,赋值给s_addr
	if(connect(sock,(struct sockaddr *)&addr,sizeof(addr)) == -1)
	{
		printf("connect failed:%s\n",strerror(errno));
		return -1;
	}

	char buf[1024] = {0};
	while(1)
	{
		read(STDIN_FILENO,buf,sizeof(buf));     //等待输入内容
		if(send(sock,buf,strlen(buf),0) == -1)  //将内容发送
		{
			printf("send failed:%s\n",strerror(errno));
			return -1;
		}

		memset(buf,0,sizeof(buf));              //将字符数组清空
		if(recv(sock,buf,sizeof(buf),0)>0)      //接收服务端发送的内容
		{
			printf("server msg:%s",buf);
		}
		else
		{	
			break;                         //接收内容不大于0,退出循环
		}
	}

	close(sock);                                   //使用完毕,关闭socket
	return 0;
}

server(tcp服务端实现)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


int main(int argc,char *argv[])
{
	if(argc <2 )                                 //接收2个参数 第2个参数为服务端监听端口号
	{
		printf("argc < 2!\n");
		return -1;
	}
	int port = atoi(argv[1]);
	int sock = socket(AF_INET,SOCK_STREAM,0);   //初始化socket

	int on = 1;
	if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) == -1)  //设置socket经历TIME_WAIT后重用socket
	{
		printf("setscoket failed:%s\n",strerror(errno));
		return -1;
	}

	struct sockaddr_in addr;      //ip地址结构
	memset(&addr,0,sizeof(addr)); //初始化ip结构
	addr.sin_family = AF_INET;    //设置结构类型类tcp/ip地址
	addr.sin_port = htons(port);  //指定一个端口号, htons将short类型从host字节类型换net字节类型 ,将本地字节顺序转换为网络字节顺序
	addr.sin_addr.s_addr = htonl(INADDR_ANY);   //服务器的所有地址
	if(bind(sock,(struct sockaddr *)&addr,sizeof(addr)) == -1) //将ip与server程序绑定
	{
		printf("bind failed:%s\n",strerror(errno));
		return -1;
	}
	if(listen(sock,20) == -1)   //开始监听
	{
		printf("listen failed:%s\n",strerror(errno));
		return -1;
	}

	char buf[1024];
	int  client_sock = 0;
	struct sockaddr_in client_addr;  //表示client的ip地址
	void *p = &client_addr;

	while(1)
	{
		memset(&client_addr,0,sizeof(client_addr)); 
	        int len = sizeof(client_addr);

		client_sock = accept(sock,p,&len); //accept会阻塞,直到客户端连接过来,返回client的socket描述符
		if(client_sock == -1)
		{
			printf("accept failed:%s\n",strerror(errno));
			return -1;
		}
		printf("accept ip:%s\n",inet_ntoa(client_addr.sin_addr));
		while(1)
		{
			memset(buf,0,sizeof(buf)); 
			int recv_result = recv(client_sock,buf,sizeof(buf),0); //recv也是阻塞的
			if(recv_result < 0) //发生错误时
			{
				printf("recv failed:%s\n",strerror(errno));
				close(client_sock);
				return -1;
			}
			else if(recv_result == 0) //连接时,为空
			{
				printf("server content:%s\n",strerror(errno));
				break;
			}
			else
			{	
				printf("server content:%s",buf);							
				memset(buf,0,sizeof(buf)); //清空字符串
				read(STDIN_FILENO,buf,sizeof(buf));  //等待输入内容
				send(client_sock,buf,sizeof(buf),0); //将输入的内容发送过去
			}
		}		
		close(client_sock);                     //使用完毕,一定要关闭
	}
	close(sock);
	return 0;
}

效果展示


秋风 2016-12-03