连接到远端的进程(socket)

一、背景

之前我讲到管道,管道是一种很便捷的进程间通信方式,使得进程之间传输数据就像给文件传输数据一样,但是管道也有其局限性,一方面它只能在相关的进程间使用,另一方面它只能连接同一台主机上的进程。所以我在这里讨论另一种进程间通信方式:socket

同时我会编写一个简单的时间服务器与对应的客户端来理解运作机理。

二、socket

socket的英文原义是“插座”,通常也称作“套接字”。用于描述IP地址和端口,可以用来实现不同虚拟机或不同计算机之间的通信。socket允许在不相关的进程见创建类似管道的连接,甚至可以通过socket连接其他主机上的进程。

三、重要概念

1、客户端与服务器

顾名思义,服务器是提供服务的进程,而客户端是被服务的对象。服务器进程等待请求,在处理完请求后循环回去等待下一个请求。客户端则无需循环,需要服务时访问服务器即可。

2、主机名和端口

运行于internet上的服务器其实是某台计算机上运行的一个进程。这里计算机被称为主机。而服务器在该主机上拥有一个端口。主机和端口的组合才标识了一个服务器。

3、协议

协议是服务器与客户端之间交互的规则。每个客户端/服务器模型都必须定义一个协议。

四、端口

我们可以通过more/etc/services来查看各个端口号及其服务。

五、编写时间服务器程序

#include<stdio.h>

#include<unistd.h>

#include<sys/types.h>

#include<sys/socket.h>

#include<netinet/in.h>

#include<netdb.h>

#include<time.h>

#include<strings.h>

#include<stdlib.h>


#define PORTNUM13000

#define HOSTLEN 256

#define oops(msg){perror(msg);exit(1);}


int main(int ac,char*av[])

{

struct sockaddr_insaddr;

struct hostent*hp;

charhostname[HOSTLEN];

intsock_id,sock_fd;

FILE *sock_fp;

char *ctime();

time_t thetime;


sock_id =socket(PF_INET,SOCK_STREAM,0);

if(sock_id == -1)

oops("socket");


bzero((void*)&saddr,sizeof(saddr));


gethostname(hostname,HOSTLEN);

hp =gethostbyname(hostname);


bcopy((void*)hp->h_addr,(void *)&saddr.sin_addr,hp->h_length);

saddr.sin_port =htons(PORTNUM);

saddr.sin_family =AF_INET;


if(bind(sock_id,(struct sockaddr *)&saddr,sizeof(saddr)) != 0)

oops("bind");


if(listen(sock_id,1) != 0)

oops("listen");


while(1){

sock_fd =accept(sock_id,NULL,NULL);

printf("Wow!got a call!\n");

if(sock_fd ==-1)

oops("accept");


sock_fp =fdopen(sock_fd,"w");

if(sock_fp ==NULL)

oops("fopen");


thetime =time(NULL);


fprintf(sock_fp,"The time here is..");

fprintf(sock_fp,"%s",ctime(&thetime));

fclose(sock_fp);

}

}

六、编写客户端程序

#include<stdlib.h>

#include<unistd.h>

#include<stdio.h>

#include<sys/types.h>

#include<sys/socket.h>

#include<netinet/in.h>

#include<netdb.h>

#include<string.h>


#define oops(msg){perror(msg);exit(1);}


int main(int ac,char*av[])

{

struct sockaddr_inservadd;

struct hostent*hp;

intsock_id,sock_fd;

charmessage[BUFSIZ];

int messlen;


sock_id =socket(AF_INET,SOCK_STREAM,0);

if(sock_id == -1)

oops("socket");


bzero(&servadd,sizeof(servadd));


hp =gethostbyname(av[1]);

if(hp == NULL)

oops(av[1]);


bcopy(hp->h_addr,(struct sockaddr*)&servadd.sin_addr,hp->h_length);

servadd.sin_port =htons(atoi(av[2]));


servadd.sin_family= AF_INET;


if(connect(sock_id,(struct sockaddr *)&servadd,sizeof(servadd))!= 0)

oops("connect");


messlen =read(sock_id,message,BUFSIZ);

if(messlen == -1)

oops("read");

if(write(1,message,messlen) != messlen)

oops("write");

close(sock_id);

}

七、测试


 我这里是在自己的主机上进行试验的。先使用hostname命令看自己的主机名,然后使用13000端口进行时间查询服务。

八、总结

这篇博客主要讲解了客户端与服务器的概念和socket的简单使用。意在继续进行深入的网络编程的学习。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值