Linux socket网络编程基础 tcp协议和udp协议
Socket TCP网络通信编程
首先,服务器端需要做以下准备工作:
(1)调用socket()函数。建立socket对象,指定通信协议。
(2)调用bind()函数。将创建的socket对象与当前主机的某一个IP地和端口绑定。
(3)调用listen()函数。使socket对象处于监听状态,并设置监听队列大小。
客户端需要做以下准备工作:
(1)调用socket()函数。建立socket()对象,指定相同通信协议。
(2)应用程序可以显式的调用bind()函数为其绑定IP地址和端口,当然,也可以将这工作交给TCP/IP协议栈。
接着建立通信连接:
(1)客户端调用connect()函数。向服务器端发出连接请求。
(2)服务端监听到该请求,调用accept()函数接受请求,从而建立连接,并返回一个新的socket文件描述符专门处理该连接。
然后通信双方发送/接收数据:
(1)服务器端调用write()或send()函数发送数据,客户端调用read()或者recv()函数接收数据。反之客户端发送数据,服务器端接收数据。
(2)通信完成后,通信双方都需要调用close()或者shutdown()函数关闭socket对象。
类比电话通信,面向连接的socket通信实现图
展示一个代码示例:
服务端:
#include<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#include<unistd.h>
#include <arpa/inet.h>
#include<pthread.h>
static void usage(const char *proc)
{
printf("Please use :%s [IP] [port]\n",proc);
}
void thread_run(void *arg)
{
printf("creat a new thread\n");
int fd = (int)arg;
char buf[1024];
while(1){
memset(buf,'\0',sizeof(buf));
ssize_t _s = read(fd,buf,sizeof(buf) - 1);
if(_s > 0){
buf[_s] = '\0';
printf("client say : %s\n",buf);
}
memset(buf,'\0',sizeof(buf));
printf("please Enter: ");
fflush(stdout);
ssize_t _s2 = read(0,buf,sizeof(buf) - 1);
if(_s2 > 0){
write(fd,buf,strlen(buf));
}
}
}
int main(int argc,char *argv[])
{
if(argc != 3){
usage(argv[0]);
exit(1);
}
//1.creat socket
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock < 0){
perror("creat socket error\n");
return 1;
}
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(atoi(argv[2]));
local.sin_addr.s_addr = inet_addr(argv[1]);
//2.bind
if(bind(sock,(struct sockaddr*)&local,sizeof(local)) < 0){
perror("bind error\n");
close(sock);
return 2;
}
//3.listen
if(listen(sock,10) < 0){
perror("listen error\n");
close(sock);
return 3;
}
printf("bind and listen success!wait accept...\n");
//4.accept
struct sockaddr_in peer;
socklen_t len = sizeof(peer);
while(1){
int fd = accept(sock,(struct sockaddr*)&peer ,&len);
if(fd < 0){
perror("accept error\n");
close(sock);
return 4;
}
printf("get connect,ip is : %s port is : %d\n",inet_ntoa(peer.sin_addr),ntohs(peer.sin_port));
pthread_t id;
pthread_create(&id,NULL,thread_run,(void*)fd);
pthread_detach(id);
}
close(sock);
return 0;
}
客户端:
#include<stdio.h>
#include<unistd.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<string.h>
#include<errno.h>
#include<netinet/in.h>
#include<arpa/inet.h>
static void usage(const char *proc)
{
printf("please use : %s [ip] [port]\n",proc);
}
int main(int argc,char *argv[])
{
if( argc != 3 ){
usage(argv[0]);
exit(1);
}
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock < 0){
perror("socket error");
return 1;
}
struct sockaddr_in remote;
remote.sin_family = AF_INET;
remote.sin_port = htons(atoi(argv[2]));
remote.sin_addr.s_addr = inet_addr(argv[1]);
int ret = connect(sock,(struct sockaddr*)&remote,sizeof(remote));
if(ret < 0){
printf("connect failed:%s\n",strerror(errno));
return 2;
}
printf("connect success!\n");
char buf[1024];
while(1){
memset(buf,'\0',sizeof(buf));
printf("please enter:");
fflush(stdout);
ssize_t _s = read(0,buf,sizeof(buf)-1);
if(_s > 0){
buf[_s - 1] = '\0';
write(sock,buf,strlen(buf));
_s = read(sock,buf,sizeof(buf)-1);
if(_s > 0){
if(strncasecmp(buf,"quit",4) == 0){
printf("qiut\n");
break;
}
buf[_s -1] = '\0';
printf("%s\n",buf);
}
}
}
close(sock);
return 0;
}
UDP网络通信编程
客户不与服务器建立链接,而是管使用sendto函数给服务器发送数据报,其中必须指定目的地址(即服务器地址)作为参数。类似的,服务器不接受来自客户的连接,而只管调用
revcfrom函数等待来自某个客户数据的到达。revcfrom将与所接受到的数据报一道返回客户的协议地址,因此服务器可以把响应发送给正确的客户。
int sendto (int s, const void *buf, int len, unsigned int flags, const struct sockaddr *to, int tolen);
int recvfrom(int s, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen);
第一个参数为发送的目标socket对象。
第二个参数为欲发送的数据信息。
第三个参数为发送数据的大小。
第四个参数为flags,如send函数所示。
第五个参数欲发送数据的目标地址,其结构体前面已经介绍。
第六个参数为此结构体的大小。
服务端代码示例:
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>
int main(int argc,char *argv[])
{
if(argc != 3){
printf("Please Enter: %s [ip] [port]",argv[0]);
return 1;
}
int sock = socket(AF_INET,SOCK_DGRAM,0);
if(sock < 0){
perror("socket error");
return 2;
}
struct sockaddr_in remote;
remote.sin_family = AF_INET;
remote.sin_port = htons(atoi(argv[2]));
remote.sin_addr.s_addr = inet_addr(argv[1]);
if(bind(sock,(struct sockaddr*)&remote,sizeof(remote)) < 0){
perror("bind error");
return 3;
}
int done = 0;
struct sockaddr_in peer;
socklen_t len = sizeof(peer);
char buf[1024];
while(!done){
memset(buf,'\0',sizeof(buf));
printf("Please Enter:");
fflush(stdout);
ssize_t _s = read(0,buf,sizeof(buf)-1 );
if(_s > 0){
buf[_s -1] = '\0';
sendto(sock,buf,sizeof(buf),0,(struct sockaddr*)&remote,sizeof(remote));
memset(buf,'\0',sizeof(buf));
recvfrom(sock,buf,sizeof(buf),0,(struct sockaddr*)&peer,&len);
printf("server echo %s,socket :&s:&d\n",buf,inet_ntoa(peer.sin_addr),ntohs(peer.sin_port));
}
}
return 0;
}
客户端代码示例: