本文内容概述:
1>单进程的套接字通信
2>多进程的套接字通信
3>多线程的套接字通信
开始学习Linux基础知识的时候,我们知道Linux下一切皆文件,并且大致可以分为几类文件:普通文件、目录、连接文件、设备和设备文件、套接字、管道。而套接字就是实现网络上进程之间的通信,套接字也是文件。在TCP/IP协议中,IP地址和端口号唯一标识网络中的一个唯一进程,IP地址和端口号就是套接字。
网络中要实现通信,少不了数据的传输。所以这里就引入了网络字节序的概念。
在前边的学习中,我们接触到大端和小端的概念。小端:数据的地位在低地址,高位在高地址;大端:数据的低位在高地址,高位在低地址。网络数据流同样也有大端和小端之分。网络数据流先发出的是低地址,后发出的是高地址。TCP/IP规定,网络数据流采用大端字节序,即就是低位在高地址。我们之所以会说到大端和小端?是因为,网络通信的时候必须知道端口号,如果发送端是大端字节序,接收端是小端字节序,那么最后看到的端口号就是不正确的端口号,所以,我们必须将端口号在发送端和接收端之间转换成统一的字节序形式。
下边提供一组接口:
(一)单进程的套接字通信
服务器:
(1)调用socket,请求系统分配文件描述符。
protocol参数: 与特定的地址家族相关的协议,TCP协议一般为IPPROTO_TCP。也可以写0,那么系统会根据地址格式和套接字类别,自动选择一个适合的协议。
(2)调用bind,绑定本机的信息,包括,IP地址类型,IP地址,端口号。
所以,这里又涉及到字符串与in_addr的转换:
(3)调用listen,监听:
(4)调用accept,接收发送连接请求的socket。
(6)read读取socket中的数据。
(7)通信完成后,调用close关闭套接字。
客户机:
(1)调用socket,请求系统分配文件描述符。
(2)调用connect,连接服务器。
(3)调用read从标准输入中读取数据,放到自定义缓冲区buf中,然后将buf中的数据写到套接字中。
(4)通信完成后,调用close关闭套接字。
代码实现:
//server.c
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int StartUp(int port,const char* ip)
{
int ListenSock = socket(AF_INET,SOCK_STREAM,0);
if(ListenSock < 0)
{
perror("socket");
exit(1);
}
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr = inet_addr(ip);
if(bind(ListenSock,(struct sockaddr*)&local,sizeof(local)) < 0)
{
perror("bind");
exit(2);
}
if(listen(ListenSock,5) < 0)
{
perror("listen");
exit(3);
}
return ListenSock;
}
int main(int argc,const char* argv[])
{
if(argc != 3)
{
printf("input error\n");
return 1;
}
int len;
int listenSock = StartUp(atoi(argv[2]),argv[1]);
struct sockaddr_in client;
while(1)
{
int sock = accept(listenSock,(struct sockaddr*)&client,&len);//获取客户机的信息
if(sock < 0)
{
perror("accept");