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; ]; ){ memset(buf,'\0',sizeof(buf)); ssize_t _s = read(fd,buf,); ){ buf[_s] = '\0'; printf("client say : %s\n",buf); } memset(buf,'\0',sizeof(buf)); printf("please Enter: "); fflush(stdout); ssize_t _s2 = read(,buf,); ){ write(fd,buf,strlen(buf)); } } } int main(int argc,char *argv[]) { ){ usage(argv[]); exit(); } //1.creat socket ); ){ perror("creat socket error\n"); ; } struct sockaddr_in local; local.sin_family = AF_INET; local.sin_port = htons(atoi(argv[])); local.sin_addr.s_addr = inet_addr(argv[]); //2.bind ){ perror("bind error\n"); close(sock); ; } //3.listen ) < ){ perror("listen error\n"); close(sock); ; } printf("bind and listen success!wait accept...\n"); //4.accept struct sockaddr_in peer; socklen_t len = sizeof(peer); ){ int fd = accept(sock,(struct sockaddr*)&peer ,&len); ){ perror("accept error\n"); close(sock); ; } 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); ; }
客户端:
#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[]) { ){ usage(argv[]); exit(); } ); ){ perror("socket error"); ; } struct sockaddr_in remote; remote.sin_family = AF_INET; remote.sin_port = htons(atoi(argv[])); remote.sin_addr.s_addr = inet_addr(argv[]); int ret = connect(sock,(struct sockaddr*)&remote,sizeof(remote)); ){ printf("connect failed:%s\n",strerror(errno)); ; } printf("connect success!\n"); ]; ){ memset(buf,'\0',sizeof(buf)); printf("please enter:"); fflush(stdout); ssize_t _s = read(,buf,); ){ buf[_s - ] = '\0'; write(sock,buf,strlen(buf)); _s = read(sock,buf,); ){ ) == ){ printf("qiut\n"); break; } buf[_s -] = '\0'; printf("%s\n",buf); } } } close(sock); ; }
UDP网络通信编程
客户不与服务器建立链接,而是管使用sendto函数给服务器发送数据报,其中必须指定目的地址(即服务器地址)作为参数。类似的,服务器不接受来自客户的连接,而只管调用
revcfrom函数等待来自某个客户数据的到达。revcfrom将与所接受到的数据报一道返回客户的协议地址,因此服务器可以把响应发送给正确的客户。
//服务端代码示例: #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[]) { ){ printf(]); ; } ); ){ perror("socket error"); ; } struct sockaddr_in local; local.sin_family = AF_INET; local.sin_port = htons(atoi(argv[])); local.sin_addr.s_addr = inet_addr(argv[]); ){ perror("bind error"); ; } ; struct sockaddr_in peer; socklen_t len = sizeof(peer); ]; while(!done){ memset(buf,'\0',sizeof(buf)); recvfrom(sock,buf,,(struct sockaddr*)&peer,&len); printf("#########################\n"); printf("get a client,socket: %s:%d\n",inet_ntoa(peer.sin_addr),ntohs(peer.sin_port)); printf("client : %s ,echo client!\n",buf); printf("#########################\n"); sendto(sock,buf,,(struct sockaddr*)&peer,len); } ; }