套接字使得客户端和服务端的进程通信要么是面向连接的,要么是面向无连接的。如果一台计算机上的客户端套接字使用某个地址访问在另一台计算机上的服务套接字,那么在指定的套接字进行应答后,这两台计算机之间就可以进行数据交换了。
套接字:
每个TCP及UDP的协议头都包含了源端口和目的端口,端口值指明了两个互相独立的TCP单元使用者。
端口号和IP地址合起来唯一的表示了Internet上的唯一的主机上的应用程序的套接字的位置。
本机地址是机器的IP地址,进程地址是要绑定的端口号。
数据报套接字使用UDP协议,因为UDP是面向数据报的,流套接字使用TCP协议,TCP协议是面向字节流的。
UDP套接字:
创建套接字:socket()
绑定套接字:bind()
发送消息:sendto() 连接发送
接收消息:recefrom() 接收数据
头文件:
udp_server.c
udp_client.c
TCP套接字:
创建套接字:socket()
绑定套接字:bind()
监听套接字:listen()
接收请求:accept()
连接:connect()
tcp_server.c
#include<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<errno.h>
#include<stdlib.h>
#include<sys/types.h>
#include<string.h>
#include<unistd.h>
void serverIO(int sock)
{
char buf[1024];
while(1)
{
ssize_t s = read(sock,buf,sizeof(buf)-1);
if(s>0)
{
buf[s] = 0;
printf("client: %s\n",buf);
write(sock,buf,strlen(buf));
}
else if (s==0)
{
printf("quit\n");
break;
}
else
{
perror("read");
break;
}
}
close(sock);
}
int main(int argc,char* argv[])
{
if(argc!=3)
{
printf("Usage %s [ip] [port]\n",argv[0]);
return 1;
}
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock<0)
{
perror("socket");
return 2;
}
printf("sock:%d\n",sock);
struct sockaddr_in server_socket;
server_socket.sin_family = AF_INET;
server_socket.sin_addr.s_addr = inet_addr( argv[1]);
server_socket.sin_port = htons(atoi(argv[2]));
//绑定端口
if(bind(sock,(struct sockaddr*)&server_socket,sizeof(server_socket))<0)
{
perror("bind");
return 3;
}
//由于这是TCP协议,所以是可靠传输,那么这里需要监听对方是否已连接
if(listen(sock,5)<0)
{
perror("listen");
return 4;
}
while(1)
{
struct sockaddr_in client_socket;
socklen_t len=sizeof(client_socket);
//作为服务器,需要先接收再发送,接收来自客户端的消息
int new_sock = accept(sock,(struct sockaddr*)&client_socket,&len);
if(new_sock<0)
{
//printf("accept error\n");
perror("accept");
//return 5;
continue;
}
//char buf_ip[INET_ADDRSTRLEN];
//inet_ntop(AF_INET,&client_socket.sin_addr,buf_ip,sizeof(buf_ip));
printf("get new connect,[ip] :%s [port]: %d\n",inet_ntoa(client_socket.sin_addr)\
,ntohs(client_socket.sin_port));
//chuangjianjincheng
pid_t id = fork();
if(id==0)
{
//child
close(sock);
if(fork()>0)
{
exit(1);
}
serverIO(new_sock);
exit(0);
}
else
{
//father
close(new_sock);//must close
waitpid(id,NULL,0);
}
}
return 0;
}
tcp_client.c
#include<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<errno.h>
#include<stdlib.h>
#include<sys/types.h>
#include<string.h>
#include<unistd.h>
int main(int argc,char* argv[])
{
if(argc!=3)
{
printf("Usage %s [ip] [port]\n",argv[0]);
return 1;
}
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock<0)
{
perror("socket");
return 2;
}
struct sockaddr_in server_socket;
server_socket.sin_family = AF_INET;
server_socket.sin_addr.s_addr = inet_addr( argv[1]);
server_socket.sin_port = htons(atoi(argv[2]));
if(connect(sock,(struct sockaddr*)&server_socket,sizeof(server_socket))<0)
{
perror("connect");
return 3;
}
printf("connect success\n");
while(1)
{
char buf[1024];
printf("client# ");
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1] = '\0';
write(sock,buf,sizeof(buf));
read(sock,buf,sizeof(buf));
printf("server# %s\n",buf);
}
close(sock);
return 0;
}
TCP VS UDP
TCP:面向连接,面向字节流,可靠传输
UDP:面向无连接,面向数据报,不可靠传输
netstat:查看网络状态的工具
-n:拒绝显示别名,能显示数字的全部转化为数字
-l:仅显示出有在listen 状态下的服务状态
-t:显示出TCP相关选项
-u:显示出UDP相关选项