目录
两台主机的进程通信
如何找到网络中的一台主机?
- IP地址
如何找到该主机上的一个进程?
- 端口号
编程的接口?
- 怎么用到系统的网络功能
tcp协议的网络编程

客户端
- 主动的一方
服务端
- 被动的一方
socket函数
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>int socket(int domain, int type, int protocol);
功能
- 创建通信的一端
参数
- @damain:通信范围,AF_UNIX:本地通信;AF_INET:IPv4;AF_INET6:IPv6
- @type:socket的类型
sock_stream:流式套接字 sock_dgram:用户数据报

- protocol:协议,表示前面类型对应的具体协议,填0表示走默认协议
sock_stream:默认走的协议是TCP
sock_dgram:默认走的协议是UDP
返回值
- 成功返回 socket对应的文件描述符
- 失败返回 -1而且errno被设置
eg:基于tcp协议的socket
int fd = socket(AF_INET,SOCK_STREAM,0);
connect(连接)
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
功能
- 发起连接请求
参数
- @socket:客户端的socket文件描述符
- @addr:代表服务器端的地址信息
- @addrlen:addr对用的地址结构体类型的大小
返回值
- 成功返回 0
- 失败返回 -1而且errno被设置

IPv4的地址结构体

网络字节序(大端模式)
字节序:大小端?
- 只要是发到网络中的数据,统一称为网络字节序(大端模式)
- 接收方收到后,转换为本机的字节序(主机字节序)
字节序的转换函数
- htons--------------端口号
- inet_addr---------IP地址
htons(端口号)
uint16_t htons(uint16_t hostshort);
功能
- 将hostshort主机字节序数值转换为网络字节序
参数
- @hostshort:要转换的数值
返回值
- 成功返回 转换好的网络字节序
- htons(5000);
inet_addr(IP地址)
in_addr_t inet_addr(const char *cp);
功能
- 将cp传过来的IPv4格式的地址转换为网络序的数值
参数
- @cp:需要的是一个点分十进制格式的 ip地址 eg:"192.168.1.122"
返回值
- 成功返回 转换好的网络字节序数值
- 失败返回 -1
cpp
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <strings.h>
//tcp客户服务端
int main(int argc, const char *argv[])
{
//1.socket
int fd = socket(AF_INET,SOCK_STREAM,0);
if(fd < 0)
{
perror("socket fail");
return -1;
}
printf("fd:%d\n",fd);
//2.bind //可选
//3.connect
struct sockaddr_in addr;//结构体
bzero(&addr,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("192.168.1.139");
addr.sin_port = htons(50000);
if(connect(fd,(const struct sockaddr*)&addr,sizeof(addr)) < 0)
{
perror("connect fail");
return -1;
}
printf("connect success \n");
return 0;
}

服务器和客户端进行交互
cpp
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <strings.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
//tcp客户服务端
int main(int argc, const char *argv[])
{
//1.socket
int fd = socket(AF_INET,SOCK_STREAM,0);
if(fd < 0)
{
perror("socket fail");
return -1;
}
printf("fd:%d\n",fd);
//2.bind //可选
//3.connect
struct sockaddr_in addr;//结构体
bzero(&addr,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("192.168.1.139");
addr.sin_port = htons(50000);
if(connect(fd,(const struct sockaddr*)&addr,sizeof(addr)) < 0)
{
perror("connect fail");
return -1;
}
printf("connect success \n");
#if 0
char buf[1024] = "hello";
write(fd,buf,sizeof(buf));
#endif
#if 1
while(1)
{
char buf[1024];
fgets(buf,sizeof(buf),stdin);
write(fd,buf,strlen(buf)+1);
if(strncmp(buf,"quit",4)==0)
{
break;
}
read(fd,buf,sizeof(buf));
printf("buf:%s\n",buf);
}
#endif
return 0;
}

bind(绑定)
- 服务器端绑定不能省略
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
功能
- 绑定一个地址(ip+port)到一个socket文件描述符上
参数
- @sockfd:socket函数获得的文件描述符
- @sockaddr:地址信息结构体

- @addrlen:表示addr参数对应类型的地址信息结构体的大小
返回值
- 成功返回 0
- 失败返回 -1而且errno被设置
listen(标记)

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>int listen(int sockfd, int backlog);
功能
- 将sockfd设置为监听套接字
参数
- @sockfd:socket创建的fd
- @backlog:队列的大小,最大128
返回值
- 成功返回 0
- 失败返回 -1而且errno被设置
accept
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能
- 获取连接请求,建立连接套接字
参数
- @socket:监听套接字
- @addr:用来获取对端的地址信息
- addrlen:值结果参数(注意:必须自己初始化一个值sizeof(addr))
返回值
- 成功返回 新连接的套接字文件描述符
- 失败返回 -1而且errno被设置
accept是一个阻塞操作,如果请求连接队列为空,此时accept会阻塞等待



client.c
cpp#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/ip.h> #include <arpa/inet.h> #include <strings.h> #include <fcntl.h> #include <unistd.h> #include <string.h> //tcp客户服务端 int main(int argc, const char *argv[]) { //1.socket int fd = socket(AF_INET,SOCK_STREAM,0); if(fd < 0) { perror("socket fail"); return -1; } printf("fd:%d\n",fd); //2.bind //可选 //3.connect struct sockaddr_in addr;//结构体 bzero(&addr,sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); addr.sin_port = htons(50000); if(connect(fd,(const struct sockaddr*)&addr,sizeof(addr)) < 0) { perror("connect fail"); return -1; } printf("connect success \n"); #if 0 char buf[1024] = "hello"; write(fd,buf,sizeof(buf)); #endif #if 1 while(1) { char buf[1024]; fgets(buf,sizeof(buf),stdin); write(fd,buf,strlen(buf)+1); if(strncmp(buf,"quit",4)==0) { break; } // read(fd,buf,sizeof(buf)); // printf("buf:%s\n",buf); } #endif return 0; }server.c
cpp#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/ip.h> #include <arpa/inet.h> #include <strings.h> #include <fcntl.h> #include <unistd.h> #include <string.h> //tcp客户服务端 int main(int argc, const char *argv[]) { //1.socket int fd = socket(AF_INET,SOCK_STREAM,0); if(fd < 0) { perror("socket fail"); return -1; } printf("fd:%d\n",fd); //2.bind(绑定) struct sockaddr_in addr;//结构体 bzero(&addr,sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); addr.sin_port = htons(50000); if(bind(fd,(const struct sockaddr*)&addr,sizeof(addr)) < 0) { perror("bind fail"); return -1; } printf("bind success \n"); //3,listen if(listen(fd,5)<0) { perror("listen fail"); return -1; } #if 0 //4.accpet int connfd = accept(fd,NULL,NULL); if(connfd < 0) { perror("accept fail"); return -1; } #endif struct sockaddr_in cliaddr; bzero(&cliaddr,sizeof(cliaddr)); socklen_t len = sizeof(cliaddr); int connfd = accept(fd,(struct sockaddr*)&cliaddr,&len); if(connfd < 0) { perror("accept fail"); return -1; } printf("connfd:%d\n",connfd); printf("-------------------\n"); printf("client ip:%s\n",inet_ntoa(cliaddr.sin_addr)); printf("client port:%d\n",ntohs(cliaddr.sin_port)); #if 0 //connect char buf[1024] = "hello"; write(fd,buf,sizeof(buf)); #endif #if 1 while(1) { char buf[1024]; //fgets(buf,sizeof(buf),stdin); //write(fd,buf,strlen(buf)+1); //if(strncmp(buf,"quit",4)==0) //{ // break; //} read(connfd,buf,sizeof(buf)); printf("buf:%s\n",buf); } #endif return 0; }
网络编程中专门的读写函数
recv(read)
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
send(write)
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
注意
网络中的收发,在tcp中我们主要用的是recv(读)和send(写)
- recv中的flags一般写0,表示默认方式(阻塞)
- send中的flags一般写0,表示默认方式
练习
