Linux下C语言Socket网络编程

Linux下socket网络编程


简介

这里打算写一个在Linux系统下运行的socket服务端,然后在win下使用网络助手与其连接,达到数据回显的功能。废话不多说了,咱们现在开始。


Linux下socket网络服务端的固定套路

  1. 创建socket。
  2. 将创建socket时返回的套接字描述符与服务器IP地址和端口进行绑定。
  3. 开始监听连接到该服务器的客户端。
  4. 当有客户端请求与该服务端程序进行连接时,接受客户端的连接
  5. 进行数据传输
  6. 关闭连接
    下面逐步对上述6个步骤使用到的函数进行分析
    1、创建socket
    int socket( int domain, int type,int protocol)
    domain:
    系统使用的底层协议族,参数一般为AF_INET(IPv4使用)或者AF_INET6(IPv6使用),当然还有其他类型的参数,这里就不一一介绍了。一般我们使用AF_INET就可以。
    type:
    指定使用的套接字类型,SOCK_STREAM字节流套接字,我们编写TCP程序时可以使用该参数。SOCK_DGRAM用户数据报文协议,使用UDP传输时,我们可以指定为该参数。
    protocol:
    使用的协议,一般该参数直接指定为 0 就好。
    2、绑定
    int bind(int sockfd, struct sockaddr *myaddr,int addrlen)
    socket:
    第一步创建socket时返回的套接字描述符。
    myaddr:
    指向绑定的服务器IP地址的结构体指针。
    addrlen:
    服务器IP地址的结构体的长度。
    3、监听
    int listen(int sockfd,int backlog)
    sockfd:
    第一步创建socket时返回的套接字描述符。
    backlog:
    设置可连接客户端的最大连接个数,当多个客户端在同一时刻连接该服务时,能够允许的个数受到该值得影响。
    4、接受客户端连接请求
    int accept(int sockfd,struct sockaddr *cliaddr,socklen_t *addrlen)
    sockfd:
    第一步创建socket时返回的套接字描述符。
    cliaddr:
    指向请求连接到该服务器端的客户端的IP地址和端口号
    addrlen:
    指向客户端IP地址和端口号的结构体长度的指针。
    5、数据传输
    int send(int sockfd, const void *msg,int len,int flags)
    int recv(int sockfd, void *buf,int len,unsigned int flags)
    sockfd:
    第一步创建socket时返回的套接字描述符。
    msg:
    发送数据的指针
    buf:
    存放接收数据的缓冲区
    len:
    数据的长度,把flags设置为0
    6、关闭连接
    int close(int fd)
    fd:
    待关闭的的socket
    小提示
    之所以要同时指定IP地址和端口号,咱们可以这样理解。比如我想使用微信给你发送一条消息,那么我们使用的电脑就必须知道你使用电脑的IP地址。但是仅仅知道IP地址并不能完成上述的要求,因为你的电脑上运行了很多的程序,计算机需要知道要把这个消息发送到你电脑上的哪一个软件,这时就需要用到端口号了。

服务端代码

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

#define MAX_CLIENT_NUM  5    //最大监听客户端连接数量为5
int main(int argc,char *argv[])
{
	char buf[512];
	int sfd;
	
	if(argc != 3)
	{
		printf("please input PORT and IP ADDR!\n");
		return 0;
	}
	
	sfd = socket(AF_INET,SOCK_STREAM,0);
	if (sfd == -1)
		printf("socker create faild!\n");
		
	struct sockaddr_in serveraddr;
	bzero(&serveraddr,sizeof(struct sockaddr_in));
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(atoi(argv[2]));   //服务器监听端口号
	serveraddr.sin_addr.s_addr = inet_addr(argv[1]); //此处IP地址必须为linux下网口ip地址
	
	if(bind(sfd,(struct sockaddr*)&serveraddr,sizeof(struct sockaddr)) == -1)
	{
		printf("bind error!\n");
		close(sfd);
	}
	
	if(listen(sfd,MAX_CLIENT_NUM) == -1)
	{
		printf("listen!\n");
		close(sfd);
		
	}
	
	int new_fd;
	struct sockaddr_in client_addr;
	int socket_len = sizeof(struct sockaddr_in);
	bzero(&client_addr,socket_len);
	
	new_fd = accept(sfd,(struct sockaddr*)&client_addr,&socket_len);
    if(new_fd == -1)
	{
		printf("--accept error-----------");
		return 0;
	}
	else      //打印请求连接的客户端IP地址和端口号
	{
		char *ptr = inet_ntoa(client_addr.sin_addr);  //IP地址,inet_ntoa函数将32位无符号的IP地址转化为X.X.X.X的形式
		unsigned short port_tmp = ntohs(client_addr.sin_port);
		printf("------------------------------------------------------\n");
		printf("client ip :%s---port:%d\n",ptr,port_tmp);
		printf("------------------------------------------------------\n");
	}
	while(1)
	{
		//数据回显功能
		int rev_num = recv(new_fd,buf,sizeof(buf),0);
		//客户端主动关闭网络连接
		if(rev_num == 0)
		{
			close(new_fd);
			break;
		}
		
		send(new_fd,buf,rev_num,0);
	}
	
	printf("client close!\n");
	close(sfd);
	return 1;
	
}

代码测试

将编译好的代码放到Linux下进行编译,并通过ifconfig查看Linux下网络的IP地址,使用ipconfig查看win下IP地址。确保其能够相互ping通。
Linux下的编译
运行编译后的程序------记得同时指定IP地址和端口号
客户端请求连接


总结

在介绍int listen(int sockfd,int backlog)函数时,我们说过其第二个参数是控制多个客户端同时请求连接时的数量的,但是在以上的代码中。我们并没有充分的使用到这个功能,那是因为TCP连接服务端程序的第4步接受客户端连接请求所使用的函数int accept(int sockfd,struct sockaddr *cliaddr,socklen_t *addrlen)默认是阻塞的。我们想要实现回显功能,就不能将其放置到 while(1)的循环中,但是放置到外面就会出现在一个时刻只能连接一个客户端。为了解决这个问题现行的方法有多进程、多线程、pollselect处理,下一章将用select函数实现网络编程的IO并发处理。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值