Linux下的socket演示程序

本节演示了Linux下的代码,server.cpp是服务器端代码,client.cpp是客户端代码,要实现的功能是:客户端从服务器读取一个字符串并打印出来。

服务器端代码 server.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(){
//创建套接字
int serv_sock = socket(AF_INET,SOCK_STREAM,IPPROTP_TCP);

//将套接字和IP、端口绑定
struct sockaddr_in serv_addr;
memset(&serv_addr,0,sizeof(serv_addr));//每个字节都用0填充
serv_addr.sin_family = AF_INET;//使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");//使用具体IP地址
serv_addr.sin_port = htons(1234);//端口
bind(serv_sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr));

//进入监听器,等待用户发起请求
listen(serv_sock,20);

//接收客户端请求
struct sockaddr_in clnt_addr;
socklen_t clnt_addr_size = sizeof(clnt_addr);
int clnt_sock = accept(serv_sock,(struct sockaddr*)&clnt_addr,&clnt_addr_size);

//向客户端发送数据
char str[] = "http://1905060202.github.io";
write(clnt_sock,str,sizeof(str));

//关闭套接字
close(slnt_sock);
close(serv_sock);

return 0;
}

客户端代码 client.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

int main(){
//创建套接字
int sock = socket(AF_INET,SOCK_STREAM,0);

//向服务器(特定的IP和端口)发起请求
struct sockaddr_in servaddr;
memset(&serv_addr,0,sizeof(serv_addr));//每个字节都用0填充
serv_addr.sin.family = AF_INET;//使用IPv4地址
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1")//具体的IP地址
serv_addr.sin_port = htons(1234);//端口
connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr));

//读取服务器传回的数据
char buffer[40];
read(sock,buffer,sizeof(buffer)-1);

printf("Message form server :%s\n",buffer);

//关闭套接字
close(sock);

return 0;
}

启动一个终端(shell),先编译server.cpp并运行:

1
2
3
[admin@loaclhost ~]$g++server.cpp -o server
[admin@localhost ~]$./client
Message form server.http://1905060202.github.io

client接收到从server发送过来的字符串就运行结束了,同时server完成发送字符串的任务也运行结束了。大家可以通过两个打开的终端来观察。

client运行后,通过connect()函数向server发起请求,处于监听状态的server被激活,执行accept()函数,接收客户端的请求,然后执行write()函数向client传回数据。client接收到传回的数据后,connect()函数就运行结束了,然后使用read()将数据读取出来。

源码解析

server.cpp:

  • 第11行通过socket()函数创建了一个套接字,参数AF_INET表示使用IPv4地址,SOCK_STREAM表示使用面向连接的套接字,IPPROTP_TCP表示使用TCP协议。在Linux中,socket也是一种文件,有文件描述符,可以使用write()或read()函数进行I/O操作。

  • 第19行通过bind()函数将套接字serv_sock与特定的IP地址和端口绑定,IP地址和端口都保存在sockaddr_in结构体中。

  • socket()函数确定了套接字的各种属性,bind()函数让套接字与特定的IP地址和端口对应起来,这样客户端才能连接到该套接字。

  • 第22行让套接字处于被动监听的状态。所谓被动监听,是指套接字一直处于“睡眠”状态,直到客户端发起请求才会被“唤醒”

  • 第27行的accept()函数用来接收客户端的请求。程序一旦执行到accept()就会被阻塞,直到客户端发起请求。

  • 第31行的write()函数用来向套接字文件中写入数据,也就是向客户端发送数据。

client.cpp:

  • 第18行代码通过connect()向服务器发起请求,服务器的IP地址和端口号保存至sockaddr_in结构体中。直到服务器传回数据后,connect()才结束运行。

  • 第22行代码通过read()从套接字中读取文件。