java socket oc_Linux C++/Java/Web/OC Socket网络编程

一,Linux C++ Socket网络编程

1.什么是TCP/IP、UDP?

TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。

UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是属于TCP/IP协议族中的一种。

下面的图表明了这些协议的关系。

a34604bae2cde92828aa469526044207.png

2.Socket在哪里呢?

ca07a57f6ff0e3e4c343bea994a073f1.png

3.Socket是什么呢?

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

门面模式,用自己的话说,就是系统对外界提供单一的接口,外部不需要了解内部的实现。

4.有很多的框架,为什么还在从Socket开始?

现在的跨平台网络编程框架很多,如Java的SSH,C/C++的Boost等。

现在的分布式框架很多,如Hadoop等。

Socket是分布式、云计算、网络编程的基础,对Socket的学习有利于对其他框架的理解。

下图是Socket编程的基本流程:

58a94ce11de0437c88354c287426e0e4.png

第一步:建立一个socket

int socket(int af, int type, int protocol)

A. 'int af'代表地址族或者称为socket所代表的域,通常有两个选项:

1. AF_UNIX - 只在单机上使用。

2. AF_INET - 可以在单机或其他使用DARPA协议(UDP/TCP/IP)的异种机通信。

B. 'int type'代表你所使用的连接类型,通常也有两种情况:

1. SOCK_STREAM - 用来建立面向连接的sockets,可以进行可靠无误的的数据传输

2. SOCK_DGRAM - 用来建立没有连接的sockets,不能保证数据传输的可靠性。

C. 'int protocol'通常设定为0。使系统选择默认的由协议族和连接类型所确定的协议。

D. 返回值是一个文件描述句柄,如果在此期间发生错误则返回-1并且设定了相应的errno。

intsockfd;if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

perror("socket 创建出错!");

exit(1);

}

第二步:绑定名字socket: bind()

int bind(int sockfd, struct sockaddr *name, int namelen)

A. sockfd是从socket()调用得到的文件描述句柄。

B. name是一个指向sockaddr类型结构的一个指针。

C. namelen给出了文件名的具体长度。

在使用AF_INET地址族的时候,类型定义如下:

structsockaddr_in {short intsin_family;

unsignedshort intsin_port;structin_addr sin_addr;

unsignedchar sin_zero[8];

};

在这个结构种,name.sin_family应当被设定为AF_INET

structsockaddr_in name;intsockfd;if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

exit(1);

}

name.sin_family=AF_INET;

name.sin_port= htons(8087);

name.sin_addr.s_addr=htonl(INADDR_ANY);

bzero(&(name.sin_zero), 8); /*zero out the rest of the space*/

if (bind(sockfd, (struct sockaddr *) &name, sizeof(structsockaddr))== -1) {

exit(1);

}

现在,如果没有问题的话,我们建立的socket就有一个名字了!相反,如果不成功,它会设定相应的错误代码,并使程序退出。

第三步:远程连接: connect()

int connect(int sockfd, struct sockaddr *serv_addr, int addrlen)

A. sockfd是我们建立的文件描述句柄

B. serv_addr是一个sockaddr结构,包含目的的地址和端口号

C. addrlen 被设定为sockaddr结构的大小。

if (connect(sockfd, (struct sockaddr *) &name, sizeof(name))< 0) {exit(1); }

第四步:监听: listen()

int listen(int sockfd, int backlog)

B. 参数backlog是指一次可以监听多少个连接

if (listen(sockfd, 20) == -1) { exit(1); }

第五步:阻塞接受连接: accept()

当有人试图从我们打开的端口登陆进来时,我们应该响应他,这个时候就要用到accept()函数了。

int accept(int sockfd, void *addr, int *addrlen)

conn = accept(sockfd, (struct sockaddr*) &name, sizeof(name));if (conn < 0) {

exit(1);

}

第六步:输入和输入的完成: send() and recv()

int send(int sockfd, const void *msg, int len, int flags)

int recv(int sockfd, void *buf, int len, unsigned int flags)

send():

sockfd - socket file descriptor

msg - message to send

len - size of message to send

flags - read 'man send' for more info, set it to 0 for now

recv():

sockfd - socket file descriptor

buf - data to receive

len - size of buf

flags - same as flags in send()

注意:如果使用的连接类型是SOCK_DGRAM,那么应该使用sendto()和recvfrom()来实现数据传输。

charbuffer[BUFFER_SIZE];while (1) {

memset(buffer,0, sizeof(buffer));int len = recv(conn, buffer, sizeof(buffer), 0);if (strcmp(buffer, "exit\n") == 0)break;

fputs(buffer, stdout);

send(conn, buffer, len,0);

}

结束: close() and shutdown()

当传输结束时,应当关闭连接。

一个服务端等待, 客户端上传文件到服务端,通过输入要上传的文件名,目前只做到仅对当前执行文件的目录下的文件,应该在服务端收到文件路径之后进行处理的。

服务端代码:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#include #include#include#include#include#include#include#include#include#include//for inet_ntoa

#include //for fork()

#define SERVER_PORT 6666

#define LISTEN_QUEUE 20

#define BUFFER_SIZE 1024

#define FILE_NAME_MAX_SIZE 512

intmain() {//设置一个socket地址结构server_addr,代表服务器internet地址, 端口

structsockaddr_in server_addr;

bzero(&server_addr, sizeof(server_addr)); //把一段内存区的内容全部设置为0

server_addr.sin_family =AF_INET;

server_addr.sin_addr.s_addr=htons(INADDR_ANY);

server_addr.sin_port=htons(SERVER_PORT);//创建用于internet的流协议(TCP)socket,用server_socket代表服务器socket

int server_socket = socket(PF_INET, SOCK_STREAM, 0);if (server_socket < 0) {

printf("Create Socket Failed!");

exit(1);

}//把socket和socket地址结构联系起来

if (bind(server_socket, (struct sockaddr*) &server_addr,sizeof(server_addr))) {

printf("Server Bind Port: %d Failed!\n", SERVER_PORT);

exit(1);

}//server_socket用于监听

if(listen(server_socket, LISTEN_QUEUE)) {

printf("Server Listen Failed!");

exit(1);

}while (1) {//定义客户端的socket地址结构client_addr

charbuffer[BUFFER_SIZE];structsockaddr_in client_addr;

socklen_t length= sizeof(client_addr);int client_socket =accept(server_socket,

(struct sockaddr*) &client_addr, &length);if (client_socket < 0) {

printf("Server Accept Failed!\n");break;

}

bzero(buffer, BUFFER_SIZE);//获取客户端要传输的文件名

length = recv(client_socket, buffer, BUFFER_SIZE, 0);if (length < 0) {

printf("Server Recieve Data Failed!\n");break;

}char file_name[FILE_NAME_MAX_SIZE + 1];

bzero(file_name, FILE_NAME_MAX_SIZE+ 1);

strncpy(file_name, buffer,

strlen(buffer)> FILE_NAME_MAX_SIZE ?FILE_NAME_MAX_SIZE : strlen(buffer));//新建文件

FILE * fp = fopen(file_name, "w");if (NULL ==fp) {

printf("File: %s CAN NOT WRITE!\n", file_name);

}else{

bzero(buffer, BUFFER_SIZE);int file_block_length = 0;while ((file_block_length =recv(client_socket, buffer, BUFFER_SIZE,0)) > 0) {if (file_block_length < 0) {

printf("Recieve Data From Client Failed!\n");break;

}int write_length = fwrite(buffer, sizeof(char),

file_block_length, fp);if (write_length

printf("File: %s Write Failed\n", file_name);break;

}

bzero(buffer, BUFFER_SIZE);

}

fclose(fp);

printf("File: %s Transfer Finished\n\n", file_name);

}

close(client_socket);

}

close(server_socket);return 0;

}

View Code

客户端

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

#include #include#include#include#include#include#include#include#include#include//for inet_ntoa

#include //for fork()

#define SERVER_PORT 6666

#define BUFFER_SIZE 1024

#define FILE_NAME_MAX_SIZE 512

intmain() {//设置一个socket地址结构client_addr,代表客户机internet地址, 端口

structsockaddr_in client_addr;

bzero(&client_addr, sizeof(client_addr)); //把一段内存区的内容全部设置为0

client_addr.sin_family = AF_INET; //internet协议族

client_addr.sin_addr.s_addr = htons(INADDR_ANY); //INADDR_ANY表示自动获取本机地址

client_addr.sin_port = htons(0); //0表示让系统自动分配一个空闲端口//创建用于internet的流协议(TCP)socket,用client_socket代表客户机socket

int client_socket = socket(AF_INET, SOCK_STREAM, 0);if (client_socket < 0) {

printf("Create Socket Failed!\n");

exit(1);

}//把客户机的socket和客户机的socket地址结构联系起来

if (bind(client_socket, (struct sockaddr*) &client_addr,sizeof(client_addr))) {

printf("Client Bind Port Failed!\n");

exit(1);

}//设置一个socket地址结构server_addr,代表服务器的internet地址, 端口

structsockaddr_in server_addr;

bzero(&server_addr, sizeof(server_addr));

server_addr.sin_family=AF_INET;

server_addr.sin_port=htons(SERVER_PORT);

socklen_t server_addr_length= sizeof(server_addr);//向服务器发起连接,连接成功后client_socket代表了客户机和服务器的一个socket连接

if (connect(client_socket, (struct sockaddr*) &server_addr,

server_addr_length)< 0) {

exit(1);

}//连接上服务器, 选择要上传的文件

char file_name[FILE_NAME_MAX_SIZE + 1];

bzero(file_name, FILE_NAME_MAX_SIZE+ 1);

printf("Please Input File Name Upload To Server:");

scanf("%s", file_name);charbuffer[BUFFER_SIZE];

bzero(buffer, BUFFER_SIZE);

strncpy(buffer, file_name,

strlen(file_name)> BUFFER_SIZE ?BUFFER_SIZE : strlen(file_name));

FILE* fp = fopen(file_name, "r");if (NULL ==fp) {

printf("File: %s NOT FOUND! \n", file_name);

exit(1);

}//发送文件名

int nameLength = send(client_socket, buffer, BUFFER_SIZE, 0);if (nameLength < 0) {

printf("File name Error! \n");

exit(0);

}

bzero(buffer, BUFFER_SIZE);int file_block_length = 0;while ((file_block_length = fread(buffer, sizeof(char), BUFFER_SIZE, fp))> 0) {if (send(client_socket, buffer, file_block_length, 0) < 0) {

printf("Send File:\t%s Failed\n", file_name);break;

}

bzero(buffer, BUFFER_SIZE);

}

printf("File:\t%s Transfer Finished\n", file_name);

fclose(fp);

close(client_socket);return 0;

}

View Code

计算机网络实验:Linux Apache下模拟服务器解析验证HTTP-Get请求并发回网页数据

HTTP请求格式:

[]

说明:第一行必须是一个请求行(request-line),用来说明请求类型,要访问的资源以及所使用的HTTP版本.

紧接着是一个首部(header)小节,用来说明服务器要使用的附加信息.

之后是一个空行.

再后面可以添加任意的其他数据[称之为主体(body)].

例1 GET请求:

GET / HTTP/1.1

Accept: */*

Accept-Language: zh-cn

Accept-Encoding: gzip, deflate

User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)

Host: www.google.cn

Connection: Keep-Alive

说明:请求的第一部分说明了该请求是一个GET请求.该行的第二部分是一个斜杠(/),用来说明请求的是该域名的根目录.该行的最后一部分说明使用的是HTTP1.1版本(另一个可选荐是1.0).

第2行是请求的第一个首部,HOST将指出请求的目的地.User-Agent,服务器端和客户端脚本都能访问它,它是浏览器类型检测逻辑的重要基础.该信息由你的浏览器来定义,并且在每个请求中自动发送.Connection,通常将浏览器操作设置为Keep-Alive

第三部分,空行,即使不存在请求主体,这个空行也是必需的.

例2 POST请求:

POST / HTTP1.1

Host:www.wrox.com

User-Agent:Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)

Content-Type:application/x-www-form-urlencoded

Content-Length:40

Connection: Keep-Alive

name=Professional%20Ajax&publisher=Wiley

说明:请求行开始处的GET改为POST,以表示不同的请求类型.

Content-Type说明了请求主体的内容是如何编码的.浏览器始终以application/x-www-form-urlencoded的格式编码来传送数据,这是针对简单URL编码的MIME类型.Content-Length说明了请求主体的字节数.

最后请求主体.名称-值对的形式.

HTTP响应格式:

[]

HTTP/1.1 200 OK

Date: Fri, 22 May 2009 06:07:21 GMT

Content-Type: text/html; charset=UTF-8

说明:HTTP状态码200,找到资源,并且一切正常.

Date:生成响应的日期和时间.

Content-Type:指定了MIME类型的HTML(text/html),编码类型是UTF-8

HTML源文体.

程序代码与简要分析

数据包分析:得到请求的文件,用户名与密码

int analysis_packet(char *packet, char *file, char *ID, char *psw)

HTTP数据包头 202根据时间与数据包内容大小构建,404返回无法连接

int headerBuilder(char *msg, int status, intsize)

与本机Java写成的运行的ServerSocket连接本机MySQL数据库校验用户名与密码

bool check(char *ID, char *psw)

主函数,作为服务端监听本机3334端口的数据请求,根据数据包请求校验与分析。

ServerSocket在本机8081端口监听,为Java与MySQL交互的服务端,对每个Socket请求开辟一个线程处理,返回校验结果。

#include #include#include#include#include#include#include#include#include#include//for inet_ntoa

#include //for fork()

#define MAXN 20480

structINFO {char ID[50], psw[50];

};int analysis_packet(char *packet, char *file, char *ID, char *psw) {char *p, *q;if ((p = strtok(packet, "\r")) ==NULL)return 0;if (strcmp(p, "GET") == 0) { //GET

if ((p = strtok(NULL, "\r")) ==NULL)return 1;

q=p;if ((p = strtok(NULL, "\r")) != NULL && strcmp(p, "HTTP/1.1") == 0) { //协议HTTP/1.1

if ((q = strtok(q, "?")) !=NULL) {

strcpy(file, q);//文件名

if ((q = strtok(NULL, "?")) !=NULL) {char *tmp;if ((tmp = strtok(q, "&")) !=NULL) {

strcpy(ID, tmp+ 3);

}if ((tmp = strtok(NULL, "&")) !=NULL) {

strcpy(psw, tmp+ 3);

}return 2;

}

}return 1;

}elseprintf("未知的协议!\n");

}elseprintf("未知的请求!\n");return 0;

}int headerBuilder(char *msg, int status, intsize) {char num[5];char *wday[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};char *wmon[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug","Sep", "Oct", "Nov", "Dec"};struct tm *ptr;

time_t it;

time(&it);

ptr= localtime(&it); //取得本地时间

switch(status) {case 200://状态行

strcat(msg, "HTTP/1.1 200 OK\r\n");//首部

strcat(msg, "Date:");

strcat(msg, wday[ptr->tm_wday]);

strcat(msg,",");

sprintf(num,"%d", ptr->tm_mday);

strcat(msg, num);

strcat(msg," ");

strcat(msg, wmon[ptr->tm_mon]);

strcat(msg," ");

sprintf(num,"%d", 1900 + ptr->tm_year);

strcat(msg, num);

strcat(msg," ");

sprintf(num,"%d", ptr->tm_hour);

strcat(msg, num);

strcat(msg,":");

sprintf(num,"%d", ptr->tm_min);

strcat(msg, num);

strcat(msg,":");

sprintf(num,"%d", ptr->tm_sec);

strcat(msg, num);

strcat(msg,"GMT\r\n");

strcat(msg,"Content-Type: text/html;charset=utf-8\r\n");

strcat(msg,"Content-Length:");

sprintf(num,"%d", size);

strcat(msg, num);

strcat(msg,"\r\n\r\n");break;case 404://状态行

strcat(msg, "HTTP/1.1 404 Not Found\r\n");//首部

strcat(msg, "Date:");

strcat(msg, wday[ptr->tm_wday]);

strcat(msg,",");

sprintf(num,"%d", ptr->tm_mday);

strcat(msg, num);

strcat(msg," ");

strcat(msg, wmon[ptr->tm_mon]);

strcat(msg," ");

sprintf(num,"%d", 1900 + ptr->tm_year);

strcat(msg, num);

strcat(msg," ");

sprintf(num,"%d", ptr->tm_hour);

strcat(msg, num);

strcat(msg,":");

sprintf(num,"%d", ptr->tm_min);

strcat(msg, num);

strcat(msg,":");

sprintf(num,"%d", ptr->tm_sec);

strcat(msg, num);

strcat(msg,"GMT\r\n\r\n");break;

}return 0;

}bool check(char *ID, char *psw) {

printf("check info %s %s\n", ID, psw);int cfd = socket(AF_INET, SOCK_STREAM, 0);intrecbytes;char buffer[50] = { '\0'};structsockaddr_in s_add;if (-1 ==cfd) {

printf("socket fail ! \r\n");return 0;

}

bzero(&s_add, sizeof(structsockaddr_in));

s_add.sin_family=AF_INET;

s_add.sin_addr.s_addr= inet_addr("127.0.0.1");

s_add.sin_port= htons(8083);if (connect(cfd, (struct sockaddr *) (&s_add), sizeof(s_add)) == -1) {

printf("connect fail !\r\n");return 0;

}

printf("connect ok !\r\n");

strcpy(buffer,"login");

printf("sending %s\n", buffer);if ((recbytes = send(cfd, buffer, 5, 0)) == -1) {return 0;

}

strcpy(buffer, ID);

buffer[strlen(ID)]= '\0';

printf("sending %s\n", buffer);if ((recbytes = send(cfd, buffer, strlen(ID), 0)) == -1) {return 0;

}

strcpy(buffer, psw);

buffer[strlen(psw)]= '\0';

printf("sending %s\n", buffer);if ((recbytes = send(cfd, buffer, strlen(psw), 0)) == -1) {return 0;

}if (-1 == (recbytes = recv(cfd, buffer, 3, 0))) {return 0;

}

close(cfd);

printf("receive %s\n", buffer);if (strcmp(buffer, "YES"))return 1;return 0;

}intmain() {intsockfd, client_fd;structsockaddr_in my_addr;structsockaddr_in remote_addr;char msg[MAXN] = { '\0'};//创建套接字

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

perror("socket create failed!");

exit(1);

}

my_addr.sin_family= AF_INET; //通信类型

my_addr.sin_port = htons(3334); //端口

my_addr.sin_addr.s_addr = INADDR_ANY; //本地地址

bzero(&(my_addr.sin_zero), 8);//绑定端口地址

if (bind(sockfd, (struct sockaddr*) &my_addr, sizeof(structsockaddr))== -1) {

exit(1);

}//开始监听

if (listen(sockfd, 10) == -1) {

exit(1);

}while (1) {

socklen_t sin_size= sizeof(structsockaddr_in);if ((client_fd = accept(sockfd, (struct sockaddr*) &remote_addr,&sin_size)) == -1) {break;

}

printf("收到%s的报文\n", (char*) inet_ntoa(remote_addr.sin_addr));//子进程段

if (!fork()) {charbuf[MAXN];char file[50] = { '\0'};char path[100] = "/Users/pcforsong/ksacm"; //服务器文件的路径//读报文

if (read(client_fd, buf, MAXN) < 0) {

perror("reading stream error!");continue;

}//printf("%s\n", buf);

FILE*fp;char ID[50] = { '\0' }, psw[50] = { '\0'};bool checked = false;int OP =analysis_packet(buf, file, ID, psw);if (OP) { //get//生成本地文件路径

strcat(path, file);

printf("path: %s\n", path);

printf("info: %s %s\n", ID, psw);if (!checked && OP == 2 && !check(ID, psw))

exit(0);checked = 1;if ((fp = fopen(path, "r")) != NULL) { //找到文件//通过文件指针计算文件大小

fseek(fp, 0, SEEK_END); //到文件结尾

int size = ftell(fp); //与文件首偏移字节数

fseek(fp, 0, SEEK_SET); //移回开头//填写msg添加200响应报文头

headerBuilder(msg, 200, size);while (fgets(buf, 2048, fp) !=NULL) {

strcat(msg, buf);

};

fclose(fp);

}else{//为msg添加404响应报文头

headerBuilder(msg, 404, 0);

}//向client发送应答报文msg//printf("%s\n", msg);

if (send(client_fd, msg, strlen(msg), 0) == -1)

perror("send error!");

close(client_fd);

}elseprintf("报文解析失败!\n");

exit(0);

}

close(client_fd);

}return 0;

}

二,JAVA ServerSocket

声明一个ServerSocket打开一个未占用的套接口,并开始ServerSocket.aceept 监听端口。

其他程序可以Socket连接IP与端口,new BufferReader(new InputStreamReader(socket.getInputStream()))接收消息。

这里使用多线程处理Socket请求,利用继承自Thread类的自定义线程类重载它的run()方法,这样虽然每个Socket都被同样的代码处理,但彼此相互独立,各自拥有各自的资源互不干扰。

实现多线程有两个办法,一种采用线程类继承Thread来实现。

另一种做法是实现Runnable接口,通过 new Thread(Runnable的子类实例) 来实现多线程。要提一句,Runnable接口可以实现对同一实例的多线程处理,即线程资源共享,是继承Thread不能做到的,所以Runnable接口被广泛使用于多线程程序。 Thread类构造函数可以为Runnable target赋值,并且Thread类的run方法就是调用target.run(),所以用Runnable接口定义的run方法是父类的。

new Thread(newRunnable(){public void run(){} //重载Thread中Runnable target的run方法

}) {public void run(){} //子类重载继承自父类的run方法

}

TCP协议

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

import java.io.*;import java.net.*;import java.sql.*;importjava.util.Vector;class ServerThread implementsRunnable {private Socket socket;//定义套接口

private BufferedReader in;//定义输入流

private PrintWriter out;//定义输出流

Connection conn;intno;public ServerThread(Socket s) throws IOException {//线程构造函数

socket = s;//取得传递参数

in = new BufferedReader(new InputStreamReader(socket.getInputStream()));//创建输入流

out = new PrintWriter(new BufferedWriter(newOutputStreamWriter(

socket.getOutputStream())),true);//创建输出流

}public void run() {//重写run方法

System.out.println("监听Socket中...");try{

Class.forName("com.mysql.jdbc.Driver");//连接数据库

conn =DriverManager.getConnection("jdbc:mysql://localhost:3306/javaicq", "root", "");while (true) {

String OP=in.readLine();//停止

if (OP.equals("end"))break;//登录

else if (OP.equals("login")) {try{

PreparedStatement prepare=conn

.prepareStatement("select nickname,password from icq where icqno=?");//设定数据库查寻条件

int g =Integer.parseInt(in.readLine());

String passwd=in.readLine().trim();

prepare.setInt(1, g);//设定参数

ResultSet rs = prepare.executeQuery();//执行数据库查寻

if (!rs.next())

out.println("用户不存在");else {//以下比较输入的号码于密码是否相同

String pass = rs.getString("password").trim();if (!passwd.equals(pass)) {

out.println("密码错误");

}else{//以及注册用户的ip 地址

PreparedStatement online =conn

.prepareStatement("update icq set ip=? where icqno=?");

online.setString(1, socket.getInetAddress()

.getHostAddress());

online.setInt(2, g);

online.executeUpdate();//set status online

PreparedStatement status =conn

.prepareStatement("update icq set status=1 where icqno=?");

status.setInt(1, g);

status.executeUpdate();

out.println("YES");

}

}

rs.close();

}catch(Exception e) {

e.printStackTrace();

out.println("Error");

}

}//新建

else if (OP.equals("new")) {try{//准备接受用户的呢称,密码,email,个人资料,籍贯,头像等信息

String nickname =in.readLine().trim();

String password=in.readLine().trim();

String email=in.readLine().trim();

String info=in.readLine().trim();

String place=in.readLine().trim();int picindex =Integer.parseInt(in.readLine());

PreparedStatement userInfo=conn

.prepareStatement("insert into icq(nickname,password,email,info,place,pic,icqno) values(?,?,?,?,?,?,?)");

userInfo.setString(1, nickname);

userInfo.setString(2, password);

userInfo.setString(3, email);

userInfo.setString(4, info);

userInfo.setString(5, place);

userInfo.setInt(6, picindex);

userInfo.setInt(7, Integer.parseInt(Double.toString(

Math.random()).substring(3, 8)));

userInfo.executeUpdate();//执行数据库添加//查询其注册的号码

PreparedStatement qNo =conn

.prepareStatement("select icqno from icq where nickname=?");

qNo.setString(1, nickname);

ResultSet rs=qNo.executeQuery();while (rs.next()) { //找到最近注册的号码

no = rs.getInt(1);

}

out.println("YES");

out.println(no);

rs.close();

}catch(Exception e) {

e.printStackTrace();

out.println("Error");

}

}

}

}catch(IOException e) {

e.printStackTrace();

}catch(SQLException e) {

e.printStackTrace();

}catch(ClassNotFoundException e) {

e.printStackTrace();

}finally{try{

conn.close();

socket.close();

}catch(IOException e) {

}catch(SQLException e) {

}

}

}

}public class Server {//主服务器类

public static void main(String args[]) throwsIOException {

ServerSocket so= new ServerSocket(8081);//在8081端口创建套接口

so.setSoTimeout(100000);

System.out.println("服务器已启动 " +so);

Socket testServer= new Socket(InetAddress.getLocalHost(), 8081);

PrintWriter out= new PrintWriter(newBufferedWriter(new OutputStreamWriter(testServer.getOutputStream())), true);try{while (true) {

Socket socket= so.accept();//无限监听客户的请求

System.out.println("建立Socket连接:" +socket);try{//out.println("login");//out.println(123);//out.println(123);

ServerThread st = new ServerThread(socket);//创建新线程处理Socket

newThread(st).start();

}catch(IOException e) {

socket.close();

}

}

}catch(SocketTimeoutException e) {

System.out.println("超时断开连接");

}finally{

so.close();

}

}

}

View Code

UDP协议

//创建UDP Socket

try{

DatagramSocket sendSocket= newDatagramSocket();

DatagramSocket receiveSocket= newDatagramSocket(udpPORT);

System.out.println("创建UDP数据报成功");

}catch(SocketException se) {

se.printStackTrace();

System.out.println("创建UDP数据报失败");

}//接收数据报

byte array[] = new byte[512];for (int x = 0; x < 512; x++)

array[x]= ' ';

DatagramPacket receivePacket= newDatagramPacket(array, array.length);

receiveSocket.receive(receivePacket);byte[] data =receivePacket.getData();

String infofromip=receivePacket.getAddress().getHostAddress()

.toString().trim();

received= new String(data, 0, data.length);//发送数据报

String info = "offline";byte[] data =info.getBytes();

sendPacket= newDatagramPacket(data, s.length(),

InetAddress

.getByName(whoaddmesip.get(i).toString()),

sendPort);

sendSocket.send(sendPacket);

二,OpenSSL编程

http://www.cnblogs.com/LittleHann/p/3741907.html

三,WebSocket

WebSocket是为解决客户端与服务端实时通信而产生的技术。其本质是先通过HTTP/HTTPS协议进行握手后创建一个用于交换数据的TCP连接,此后服务端与客户端通过此TCP连接进行实时通信。

WebSocket规范当前还没有正式版本,草案变化也较为迅速。Tomcat7(本文中的例程来自7.0.42)当前支持RFC 6455定义的WebSocket,而RFC 6455目前还未冻结,将来可能会修复一些Bug,甚至协议本身也可能会产生一些变化。

RFC6455定义的WebSocket协议由握手和数据传输两个部分组成。

来自客户端的握手信息类似如下:

GET /chat HTTP/1.1

Host: server.example.com

Upgrade: websocket

Connection: Upgrade

Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==

Origin: http://example.com

Sec-WebSocket-Protocol: chat, superchat

Sec-WebSocket-Version: 13

服务端的握手信息类似如下:

HTTP/1.1 101 Switching Protocols

Upgrade: websocket

Connection: Upgrade

Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

Sec-WebSocket-Protocol: chat

一旦客户端和服务端都发送了握手信息并且成功握手,则数据传输部分将开始。数据传输对客户端和服务端而言都是一个双工通信通道,客户端和服务端来回传递的数据称之为“消息”。

客户端通过WebSocket URI发起WebSocket连接,WebSocket URIs模式定义如下:

ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ]

wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ]

ws是普通的WebSocket通信协议,而wss是安全的WebSocket通信协议(就像HTTP与HTTPS之间的差异一样)。在缺省情况下,ws的端口是80而wss的端口是443。

关于WebSocke协议规范的完整详尽说明,请参考RFC 6455。

Tomcat7提供的与WebSocket相关的类均位于包org.apache.catalina.websocket之中(包org.apache.catalina.websocket的实现包含于文件catalina.jar之中),它包含有类Constants、MessageInbound、StreamInbound、WebSocketServlet、WsFrame、WsHttpServletRequestWrapper、WsInputStream、WsOutbound。这些类的关系如图 1所示。

8e0f2edcdeacf14322746babd768a7c4.png

图1

包org.apache.catalina.websocket中的这些类为WebSocket开发服务端提供了支持,这些类的主要功能简述如下:

Constants:包org.apache.catalina.websocket中用到的常数定义在这个类中,它只包含静态常数定义,无任何逻辑实现。

MessageInbound:基于消息的WebSocket实现类(带内消息),应用程序应当扩展这个类并实现其抽象方法onBinaryMessage和onTextMessage。

StreamInbound:基于流的WebSocket实现类(带内流),应用程序应当扩展这个类并实现其抽象方法onBinaryData和onTextData。

WebSocketServlet:提供遵循RFC6455的WebSocket连接的Servlet基本实现。客户端使用WebSocket连接服务端时,需要将WebSocketServlet的子类作为连接入口。同时,该子类应当实现WebSocketServlet的抽象方法createWebSocketInbound,以便创建一个inbound实例(MessageInbound或StreamInbound)。

WsFrame:代表完整的WebSocket框架。

WsHttpServletRequestWrapper:包装过的HttpServletRequest对象。

WsInputStream:基于WebSocket框架底层的socket的输入流。

WsOutbound:提供发送消息到客户端的功能。它提供的所有向客户端的写方法都是同步的,可以防止多线程同时向客户端写入数据。

Tomcat是怎样实现WebSocket的

1)要开始使用WebSocket,你必须继承Tomcat的WebSocket类

2)编写自己的类,它继承WebSocketServlet类(由于这是一个Servlet,因此必须把它映射到URL)

3)实现一个消息监听器类,由于它继承自WebSocketServlet类,因此需要自己实现createWebSocketInbound()方法

此方法能够用于监听事件。有两个必须有的方法:

一是 protected void onBinaryData(InputStream inStream);

二是protected void onTextData(Reader reader);

当WebSocket打开或关闭时,如果你希望收到通知,只需简单地重写onOpen()方法和onClose()方法。

把数据写到客户端,必须有StreamInbound实现类,它会引用发送器组件WsOutbound,可以简单地通过调用来取到它:myStreamInbound.getWsOutbound()

还可以发送二进制数据writeBinaryData(int b);

或者发送文本数据到客户端writeTextData(char c);

注意:这些方法是互斥的。不要同时调用两种方法,以期待既发送二进制数据,又发送文本数据。

packagecom.ibcio;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServletRequest;importorg.apache.catalina.websocket.StreamInbound;

@WebServlet(urlPatterns= { "/message"})//如果要接收浏览器的ws://协议的请求就必须实现WebSocketServlet这个类

public class WebSocketMessageServlet extendsorg.apache.catalina.websocket.WebSocketServlet {private static final long serialVersionUID = 1L;public static int ONLINE_USER_COUNT = 1;publicString getUser(HttpServletRequest request) {return (String) request.getSession().getAttribute("user");

}//跟平常Servlet不同的是,需要实现createWebSocketInbound,在这里初始化自定义的WebSocket连接对象

@OverrideprotectedStreamInbound createWebSocketInbound(String subProtocol,

HttpServletRequest request) {return new WebSocketMessageInbound(this.getUser(request));

}

}

JS

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

varwebsocket;//初始话WebSocket

functioninitWebSocket() {if(window.WebSocket) {

websocket= new WebSocket(encodeURI('ws://localhost:8080/WebSocket/message'));

websocket.onopen= function() {//连接成功

win.setTitle(title + '  (已连接)');

}

websocket.οnerrοr= function() {//连接失败

win.setTitle(title + '  (连接发生错误)');

}

websocket.onclose= function() {//连接断开

win.setTitle(title + '  (已经断开连接)');

}//消息接收

websocket.onmessage = function(message) {var message =JSON.parse(message.data);//接收用户发送的消息

if (message.type == 'message') {

output.receive(message);

}else if (message.type == 'get_online_user') {//获取在线用户列表

var root =onlineUser.getRootNode();

}else if (message.type == 'user_join') {//用户上线

var root =onlineUser.getRootNode();var user =message.user;var node =root.createNode({

id : user,

text : user,

iconCls :'user',

leaf :true});

root.appendChild(node);

}else if (message.type == 'user_leave') {//用户下线

var root =onlineUser.getRootNode();var user =message.user;var node = root.findChild('id',user);

root.removeChild(node);

}

}

}

};//发送消息

functionsend() {var message ={};if (websocket != null) {if(input.getValue()) {

Ext.apply(message, {

from : user,

content : input.getValue(),

timestamp :newDate().getTime(),

type :'message'});

websocket.send(JSON.stringify(message));//output.receive(message);

input.setValue('');

}

}else{

Ext.Msg.alert('提示', '您已经掉线,无法发送消息!');

}

}

});

View Code

四、Objective-C Socket编程

iPhone的标准推荐CFNetwork C库编程.但是编程比较烦躁。在其它OS往往用类来封装的对Socket函数的处理。比如MFC的CAsysncSocket.在iphone也有类似于开源项目.cocoa AsyncSocket库, 官方网站:http://code.google.com/p/cocoaasyncsocket/ 它用来简化CFnetwork的调用.

//建立基于UDP的Socket连接

-(void)openUDPServer{//初始化udp

AsyncUdpSocket *tempSocket=[[AsyncUdpSocket alloc] initWithDelegate:self];

self.udpSocket=tempSocket;

[tempSocket release];//绑定端口

NSError *error =nil;

[self.udpSocket bindToPort:4333 error:&error];//发送广播设置

[self.udpSocket enableBroadcast:YES error:&error];//加入群里,能接收到群里其他客户端的消息

[self.udpSocket joinMulticastGroup:@"127.0.0.1" error:&error];//启动接收线程

[self.udpSocket receiveWithTimeout:-1 tag:0];

}//通过UDP,发送消息

-(void)sendMassage:(NSString *)message

{

NSDate*nowTime =[NSDate date];

NSMutableString*sendString=[NSMutableString stringWithCapacity:100];

[sendString appendString:message];//开始发送

BOOL res =[self.udpSocket sendData:[sendString dataUsingEncoding:NSUTF8StringEncoding]

toHost:@"127.0.0.1"port:4333withTimeout:-1tag:0];if (!res) {

UIAlertView*alert = [[UIAlertView alloc] initWithTitle:@"提示"message:@"发送失败"

delegate:self

cancelButtonTitle:@"取消"otherButtonTitles:nil];

[alert show];

[alert release];

}

}

其委托方法

#pragma mark UDP Delegate Methods

- (BOOL)onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port

{

[self.udpSocket receiveWithTimeout:-1 tag:0];

NSLog(@"host---->%@",host);//接收到数据回调

NSString *info=[[[NSString alloc] initWithData:data encoding: NSUTF8StringEncoding] autorelease];

returnYES;

}- (void)onUdpSocket:(AsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError *)error

{//无法发送时,返回的异常提示信息

}- (void)onUdpSocket:(AsyncUdpSocket *)sock didNotReceiveDataWithTag:(long)tag dueToError:(NSError *)error

{//无法接收时,返回异常提示信息

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值